[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/4] chachapoly: handle packet encryption with authenticated encryption mode
[Thread Prev] | [Thread Next]
- Subject: [PATCH 2/4] chachapoly: handle packet encryption with authenticated encryption mode
- From: Meng Hourk Tan <mtan@xxxxxxxxxx>
- Reply-to: libssh@xxxxxxxxxx
- Date: Mon, 18 Sep 2017 09:49:19 +0000
- To: "libssh@xxxxxxxxxx" <libssh@xxxxxxxxxx>
From a991c4af004f7f761a702f3f4a4cb9747068c1f2 Mon Sep 17 00:00:00 2001 From: Meng Tan <mtan@xxxxxxxxxx> Date: Mon, 18 Sep 2017 11:34:50 +0200 Subject: [PATCH 2/4] chachapoly: handle packet encryption with authenticated encryption mode Signed-off-by: Meng Tan <mtan@xxxxxxxxxx> --- src/packet.c | 81 +++++++++++++++++++++++++++++++++++------------------- src/packet_crypt.c | 37 +++++++++++++++++++------ 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/packet.c b/src/packet.c index 6e84dc8..592d7d7 100644 --- a/src/packet.c +++ b/src/packet.c @@ -110,7 +110,7 @@ static ssh_packet_callback default_packet_handlers[]= { ssh_packet_global_request, // SSH2_MSG_GLOBAL_REQUEST 80 #else /* WITH_SERVER */ NULL, -#endif /* WITH_SERVER */ +#endif /* WITH_SERVER */ ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81 ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82 NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89 @@ -144,6 +144,11 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) ssh_session session= (ssh_session) user; unsigned int blocksize = (session->current_crypto ? session->current_crypto->in_cipher->blocksize : 8); + unsigned int authlen = (session->current_crypto ? + session->current_crypto->in_cipher->authlen : 0); + unsigned int aadlen = authlen ? 4 : 0; + /* needlen is the number of bytes needed to read length */ + unsigned int needlen = aadlen ? aadlen : blocksize; unsigned char mac[DIGEST_MAX_LEN] = {0}; char buffer[16] = {0}; size_t current_macsize = 0; @@ -155,7 +160,8 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) size_t processed = 0; /* number of byte processed from the callback */ if(session->current_crypto != NULL) { - current_macsize = hmac_digest_len(session->current_crypto->in_hmac); + current_macsize = (authlen ? 0 : + hmac_digest_len(session->current_crypto->in_hmac)); } if (data == NULL) { @@ -168,7 +174,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) switch(session->packet_state) { case PACKET_STATE_INIT: - if (receivedlen < blocksize) { + if (receivedlen < needlen) { /* * We didn't receive enough data to read at least one * block size, give up @@ -190,11 +196,12 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) } } - memcpy(buffer, data, blocksize); - processed += blocksize; + memcpy(buffer, data, needlen); + processed += needlen; len = ssh_packet_decrypt_len(session, buffer); - rc = ssh_buffer_add_data(session->in_buffer, buffer, blocksize); + /* buffer (packet_len) is still encrypted for chachapoly */ + rc = ssh_buffer_add_data(session->in_buffer, buffer, needlen); if (rc < 0) { goto error; } @@ -207,7 +214,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } - to_be_read = len - blocksize + sizeof(uint32_t); + to_be_read = len - needlen + sizeof(uint32_t); if (to_be_read < 0) { /* remote sshd sends invalid sizes? */ ssh_set_error(session, @@ -223,8 +230,8 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) FALL_THROUGH; case PACKET_STATE_SIZEREAD: len = session->in_packet.len; - to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize; - /* if to_be_read is zero, the whole packet was blocksize bytes. */ + to_be_read = len - needlen + sizeof(uint32_t) + current_macsize + authlen; + /* if to_be_read is zero, the whole packet was needlen bytes. */ if (to_be_read != 0) { if (receivedlen - processed < (unsigned int)to_be_read) { /* give up, not enough data in buffer */ @@ -238,10 +245,10 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) packet, to_be_read - current_macsize); #endif - + /* add mac for Authenticated Encryption Mode (AEM) */ rc = ssh_buffer_add_data(session->in_buffer, - packet, - to_be_read - current_macsize); + packet, + to_be_read - current_macsize); if (rc < 0) { goto error; } @@ -254,11 +261,12 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) * have been decrypted) */ uint32_t buffer_len = ssh_buffer_get_len(session->in_buffer); + uint32_t offset = aadlen ? 0 : blocksize; /* The following check avoids decrypting zero bytes */ - if (buffer_len > blocksize) { - uint8_t *payload = ((uint8_t*)ssh_buffer_get(session->in_buffer) + blocksize); - uint32_t plen = buffer_len - blocksize; + if (buffer_len > offset) { + uint8_t *payload = ((uint8_t*)ssh_buffer_get(session->in_buffer) + offset); + uint32_t plen = buffer_len - offset - authlen; rc = ssh_packet_decrypt(session, payload, plen); if (rc < 0) { @@ -266,17 +274,20 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } } - - /* copy the last part from the incoming buffer */ - packet = ((uint8_t *)data) + processed; - memcpy(mac, packet, current_macsize); - - rc = ssh_packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac); - if (rc < 0) { - ssh_set_error(session, SSH_FATAL, "HMAC error"); - goto error; + /* mac already verified in decryption for AEM */ + if (authlen == 0) { + /* copy the last part from the incoming buffer */ + packet = ((uint8_t *)data) + processed; + memcpy(mac, packet, current_macsize); + + rc = ssh_packet_hmac_verify(session, session->in_buffer, mac, + session->current_crypto->in_hmac); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, "HMAC error"); + goto error; + } + processed += current_macsize; } - processed += current_macsize; } /* skip the size field which has been processed before */ @@ -290,6 +301,11 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } + if (authlen != 0) { + /* skip the mac at the end for AEM */ + ssh_buffer_pass_bytes_end(session->in_buffer, authlen); + } + if (padding > ssh_buffer_get_len(session->in_buffer)) { ssh_set_error(session, SSH_FATAL, @@ -545,8 +561,12 @@ static int packet_send2(ssh_session session) { unsigned char *hmac = NULL; char padstring[32] = { 0 }; int rc = SSH_ERROR; - uint32_t finallen,payloadsize,compsize; + uint32_t finallen,payloadsize,compsize,headsize; uint8_t padding; + unsigned int authlen = (session->current_crypto ? + session->current_crypto->out_cipher->authlen : 0); + unsigned int aadlen = authlen ? 4 : 0; + unsigned int hmac_len = (authlen ? authlen : hmac_digest_len(hmac_type)); uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 }; @@ -562,7 +582,12 @@ static int packet_send2(ssh_session session) { } #endif /* WITH_ZLIB */ compsize = currentlen; - padding = (blocksize - ((currentlen +5) % blocksize)); + + /* size of packet_len (4 bytes) and padding_len (1 byte) */ + /* packet_len not encrypted for EtM or AEM */ + headsize = 5 - aadlen; + + padding = (blocksize - ((currentlen + headsize) % blocksize)); if(padding < 4) { padding += blocksize; } @@ -593,7 +618,7 @@ static int packet_send2(ssh_session session) { hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); if (hmac) { - rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_digest_len(hmac_type)); + rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_len); if (rc < 0) { goto error; } diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 1ac9185..6265844 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -57,14 +57,23 @@ uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted){ return ntohl(decrypted); } +/* + * 'data' contains: + * - aadlen packet len part (EtM or AEM) + * - payload to decrypt ((len - aadlen) size) + * - authlen mac for AEM + */ int ssh_packet_decrypt(ssh_session session, void *data,uint32_t len) { struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher; char *out = NULL; + /* TODO: aadlen and authlen should be passed in parameters */ + unsigned int aadlen; int res = 0; assert(len); + aadlen = crypto->authlen ? 4 : 0; - if(len % session->current_crypto->in_cipher->blocksize != 0){ + if(len % crypto->blocksize != aadlen){ ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len); return SSH_ERROR; } @@ -89,11 +98,17 @@ int ssh_packet_decrypt(ssh_session session, void *data,uint32_t len) { return 0; } +/* + * 'data' can contains: + * - packet_len part (for EtM or AEM of aadlen size) + * - payload to encrypt ((len - aadlen) size) + */ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) { struct ssh_cipher_struct *crypto = NULL; HMACCTX ctx = NULL; - char *out = NULL; - unsigned int finallen; + unsigned char *out = NULL; + /* TODO: aadlen and authlen should be passed in parameters */ + unsigned int finallen, aadlen, authlen; uint32_t seq; enum ssh_hmac_e type; int res = 0; @@ -103,20 +118,23 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) if (!session->current_crypto) { return NULL; /* nothing to do here */ } - if(len % session->current_crypto->in_cipher->blocksize != 0){ + crypto = session->current_crypto->out_cipher; + authlen = crypto->authlen; + aadlen = authlen ? 4 : 0; + + if(len % crypto->blocksize != aadlen){ ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len); return NULL; } - out = malloc(len); + out = malloc(len + authlen); if (out == NULL) { return NULL; } type = session->current_crypto->out_hmac; seq = ntohl(session->send_seq); - crypto = session->current_crypto->out_cipher; - if (session->version == 2) { + if (session->version == 2 && authlen == 0) { ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { SAFE_FREE(out); @@ -142,7 +160,10 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) } memcpy(data, out, len); - BURN_BUFFER(out, len); + if (session->version == 2 && authlen) { + memcpy(session->current_crypto->hmacbuf, out + len, authlen); + } + BURN_BUFFER(out, len + authlen); SAFE_FREE(out); if (session->version == 2) { -- 2.1.4
Archive administrator: postmaster@lists.cynapses.org