Socket.h 12.9 KB
/** @file 
* \brief Header de la clase Socket
* \author Imanol Barba Sabariego
* \date 12/06/2013
*
* En este fichero se define la clase Socket, que es la clase que se abstraer toda la comunicación con sockets al programador
*/
#ifndef SOCKET_H_
#define SOCKET_H_

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <rsa.h>
#include <sha.h>
#include <filters.h>
#include <files.h>
#include <osrng.h>
#include <secblock.h>
#include <cryptlib.h>
#include <aes.h>
#include <modes.h>

//! Longitud de la llave RSA
/*! \brief Longitud en bits de la llava RSA usada para encriptar la llave AES. Una longitud de 0 indica que el mensaje se trasnmitirá SIN encriptar.

__NOTA: Si se usara una longitud menor a 728 bits habria que modificar el método que envía y recibe la llave AES, ya que la longitud máxima del
mensaje a encriptar con RSA no sería suficiente para transmitir la llave y el IV en un solo paquete. De todas formas, se recomienda NO USAR una
llave de longitud inferior a 768 bits, la llave RSA de 512 bits se puede descifrar con un Pentium 4 en unas 8 horas.__ */
#define RSALENGTH 1024
//! Longitud de la llave AES
/*! \brief Longitud en bytes de la llave AES usada para encriptar el mensaje. Los valores permitidos son 16, 24 y 32 */
#define AESLENGTH 16
//! Longitud del paquete encriptado con RSA
/*! \brief Longitud en bytes del tamaño de cada paquete encriptado con RSA, esto sólo se usaría para la transmisión de la llave AES */
#define MAXLENGTH (RSALENGTH/8)

using namespace CryptoPP;
using namespace std;

//! Clase del socket
/**
Esta clase define un objeto con los métodos y atributos necesarios para realizar comunicación encriptada o en texto llano a través de un socket TCP/IP
en un entorno UNIX abstrayendo la implementación de sockets y de encriptación al programador.
*/
class Socket
{
        private:
                //! Descriptor del fichero del socket
                /*! Esta variable contiene el file descriptor del socket abierto por el SO. */
                int sock;
                //! Estructura de dirección de socket
                /*! Este struct es usado por el SO para gestionar la dirección del socket abierto. */
                struct sockaddr_in sockAddr;
                //! Pseudo-generador de números aleatorios
                /*! Esta variable se usa para generar los números aleatorios necesarios para la creación de las llaves criptográficas. */
                AutoSeededRandomPool rng;
                //! Llave privada RSA
                /*! Esta variable contiene la llave privada RSA generada. */
                RSA::PrivateKey privateKey;
                //! Llave pública RSA própia
                /*! Esta variable contiene la llave RSA pública generada por el própio socket. */
                RSA::PublicKey myPublicKey;
                //! Llave pública RSA del peer
                /*! Esta variable contiene la llave RSA pública recibida del peer al otro lado del socket. */
                RSA::PublicKey theirPublicKey;
                //! Llave AES própia
                /*! Esta variable contiene la llave AES generada por el própio socket. */
                byte myKey[AESLENGTH];
                //! IV própio
                /*! Esta variable contiene el IV generado por el própio socket. */
		byte myIV[ AES::BLOCKSIZE ];
                //! Llave AES del peer
                /*! Esta variable contiene la llave AES recibida del peer al otro lado del socket. */
		byte theirKey[AESLENGTH];
                //! IV del peer
                /*! Esta variable contiene el IV recibido del peer al otro lado del socket. */
		byte theirIV[ AES::BLOCKSIZE ];
                //! Método de encriptación RSA
                /*! Este método devuelve el mensaje que se le pasa por argumento encriptado con RSA en forma de string. */
                string encryptRSA(string& text /*!<Texto a encriptar*/);
                //!Método de desencriptación RSA
                /*! Este método devuelve el mensaje que se la pasa por argumento desencriptado con RSA en forma de string. */
                string decryptRSA(string& crypt/*!<Mensaje a desencriptar*/);
                //! Método de encriptación AES
                /*! Este método devuelve el mensaje que se le pasa por argumento encriptado con AES en forma de string. */
                string encryptAES(const string& text/*!<Texto a encriptar*/);
                //! Método de desencriptación AES
                /*! Este método devuelve el mensaje que se la pasa por argumento desencriptado con AES en forma de string. */
                string decryptAES(const string& crypt/*!<Mensaje a desencriptar*/);
                //! Método para recibir un mensaje de longitud conocida
                /*! \brief Este método se usa para recibir un mensaje de la longitud que se especifica por argumento y almacenarlo en el buffer 
                proporcionado.

                _Este método garantiza que todo el mensaje se recibirá entero aunque la red no admita una longitud de paquete tan grande._*/
                int Receive(char *buff/*!<Buffer donde se almacena el mensaje recibido*/, int length/*!<Longitud del mensaje a recibir*/);
                //! Método para enviar un mensaje de longitud conocida
                /*! \brief Este método se usa para enviar un mensaje de la longitud especifidada en el argumento y devuelve el número de bytes 
                enviados.

                _Este método garantiza que todo el mensaje se enviará entero aunque la red no admita una longitud de paquete tan grande._*/
                int Send(const char *buff/*!<Buffer con el mensaje a enviar*/, int length/*!<Longitud del mensaje*/);
                //! Método para enviar un un string en texto llano
                /*! Este método se sirve de Send() para enviar un mensaje sin encriptar usando el \ref proto "protocolo" implementado. */
                void SendUnencrypted(const string& text/*!<Texto a enviar*/);
                //! Método para recibir un string en texto llano
                /*! Este método se sirve del método Receive() para recibir un mensaje sin encriptar de longitud arbitrária usando el
                \ref proto "protocolo" implementado. */
                void ReceiveUnencrypted(string& text/*!<String donde se almacena el texto recibido*/);
                //! Método para cargar llaves RSA
                /*! Este método lee del disco una llave RSA y la asigna al Socket que lo invoca. */
                void LoadKey(const string& filename/*!<Ruta absoluta o relativa a la llave*/, PublicKey *key/*!<Llave donde se almacenan los datos leídos*/);
                //! Método para guardar llaves RSA
                /*! Este método guarda al disco una llave RSA proporcionada por argumento. */
                void SaveKey(const string& filename/*!<Ruta absoluta o relativa a la llave*/, const PublicKey *key/*!<Llave a almacenar*/);

        public:
                //! Constructor de la clase Socket
                /*! Inicializa el file descriptor del socket y prepara la memoria donde se almacenarán las llaves públicas. */
                Socket();
                //! Método para crear sockets
                /*! Crea un file descriptor para un socket que por defecto no está conectado ni asignado a ninguna dirección. */
                void Create();
                //! Método para hacer bind a una dirección y puerto
                /*! Este método asigna el socket a una dirección IP (y por tanto, a una interfaz de red en concreto) y un puerto, para que 
                posteriormente actúe de servidor escuchando conexiones. */
                void Bind(string address/*!<Dirección IP asignada*/, int port/*!<Puerto asignado*/);
                //! Método para escuchar conexiones
                /*! Este método configura el socket para que se ponga en modo escucha y así pueda atender conexiones entrantes. */
                void Listen(int backlog/*!<Número máximo de conexiones __en espera__*/);
                //! Método para aceptar conexiones
                /*! Este método bloquea el thread que lo ejecuta hasta que recibe una conexión entrante, que almacena como instancia de la clase
                Socket en la referencia proporcionada por argumento. */
                void Accept(Socket &clientSock/*!<Instáncia de Socket que comunica con el cliente entrante*/);
                //! Método para efectuar conexiones
                /*! Este método sirve a los sockets que actúan como cliente para poder efectuar conexiones a otro socket que esté escuchando en la 
                dirección y puerto especificados y atienda conexiones. */
                void Connect(string hostname/*!<Hostname al que conectarse*/, int port/*!<Puerto al que conectarse*/);
                //! Método para cerrar sockets
                /*! Este método cierra el socket para que no se pueda escribir ni leer más en él, para liberarlo del kernel y terminar la conexión TCP. */
                void Close();
                //! Getter para el file descriptor del socket
                /*! Este método devuelve el file descriptor del socket. */
                int getSock();
                //! Método para generar las llaves RSA
                /*! Este método genera las llaves pública y privada RSA y las asigna la instancia de Socket que lo ha invocado. */
                void generateRSAKeys();
                //! Método para generar las llaves AES
                /*! Este método genera la llave y el IV de AES y los asigna a la instancia de Socket que lo ha invocado. */
                void generateAESKeys();
                //! Método para mandar la llave pública
                /*! Este método manda la llave pública RSA sin encriptar por el socket. */
                bool sendPublicKey();
                //! Método para recibir la llave pública
                /*! Este método sirve para recibir la llave pública RSA de otro Socket. */
                bool receivePublicKey();
                //! Método para transferir llaves entre objetos Socket
                /*! Este método sirve para que dos instancias de Socket intercambien sus llaves criptológicas dentro de la misma 
                máquina. 

                _Se usa para cuando un Socket de tipo servidor genere una instancia de otro Socket para comunicarse con el cliente, el primero
                le transfiera las llaves generadas al segundo para poder realizar la comunicación._*/
                void setKeys(RSAFunction *pubkey/*!<Llave pública RSA*/, InvertibleRSAFunction *privkey/*!<Llave privada RSA*/, byte *key/*!<Llave AES*/, byte *iv/*!<IV AES*/);
                //! Getter de la llave pública RSA
                /*! Este método devuelve la llave pública RSA para poder transferirla a otro Socket usando setKeys(). */
                RSAFunction* getPublicKey();
                //! Getter de la llave privada RSA
                /*! Este método devuelve la llave privada RSA para poder transferirla a otro Socket usando setKeys(). */
                InvertibleRSAFunction* getPrivateKey();
                //! Método para mandar la llave AES
                /*! Este método manda la llave AES y el IV del Socket que lo invoca encriptados con RSA. */
                void sendAES();
                //! Método para recibir la llave AES
                /*! Este método sirve para recibir la llave AES y el IV de otro Socket encriptados por RSA. */
                void recvAES();
                //! Getter de la llave AES
                /*! Este método devuelve la llave AES para poder transferirla a otro Socket usando setKeys(). */
                byte* getAESKey();
                //! Getter del IV AES
                /*! Este método devuelve el IV AES para poder transferirla a otro Socket usando setKeys(). */
                byte* getAESIV();
                //! Método para cargar las llaves del disco
                /*! Este método lee las llaves RSA del disco o las genera y guarda de nuevo si no existen o son inválidas. También genera
                las llaves AES. */
                void loadKeys(string pub/*!<Ruta absoluta o relativa a la llave pública RSA*/, string priv/*!<Ruta absoluta o relativa a la llave privada RSA*/);
                //! Método para enviar mensajes
                /*! Este método envía el mensaje que se le proporciona a través del Socket con o sin encriptación según 
                las \ref defines "opciones de compilación" usando el \ref proto "protocolo" implementado. */
                const Socket& operator << ( const string& /*!<Mensaje a enviar*/);
                //! Método para recibir mensajes
                /*! Este método recibe un mensaje de longitud arbitrária con o sin encriptación según las \ref defines "opciones de compilación" usando
                el \ref proto "protocolo" implementado. */
                const Socket& operator >> ( string& /*!<Mensaje a recibir*/);
};
#endif /* SOCKET_H_ */