diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2018-02-28 10:24:54 -0600 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2018-06-28 09:06:30 +0200 |
commit | 8a735d5eb7e7033d7bcda6de6df622a84d264bf1 (patch) | |
tree | 81dec0119db92789e218f6a583355c4b2407c2a1 /src/packet_crypt.c | |
parent | d038c4dee76ff8dff93101f5807a78f21064824c (diff) | |
download | libssh-8a735d5eb7e7033d7bcda6de6df622a84d264bf1.tar.gz libssh-8a735d5eb7e7033d7bcda6de6df622a84d264bf1.tar.xz libssh-8a735d5eb7e7033d7bcda6de6df622a84d264bf1.zip |
chacha: packet decryption
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'src/packet_crypt.c')
-rw-r--r-- | src/packet_crypt.c | 125 |
1 files changed, 94 insertions, 31 deletions
diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 5bcb6d65..fb09a225 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -44,40 +44,97 @@ #include "libssh/crypto.h" #include "libssh/buffer.h" -uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted){ - uint32_t decrypted; - - if (session->current_crypto) { - if (ssh_packet_decrypt(session, crypted, - session->current_crypto->in_cipher->blocksize) < 0) { - return 0; +/** @internal + * @brief decrypt the packet length from a raw encrypted packet, and store the first decrypted + * blocksize. + * @returns native byte-ordered decrypted length of the upcoming packet + */ +uint32_t ssh_packet_decrypt_len(ssh_session session, + uint8_t *destination, + uint8_t *source) +{ + uint32_t decrypted; + int rc; + + if (session->current_crypto != NULL) { + if (session->current_crypto->in_cipher->aead_decrypt_length != NULL) { + rc = + session->current_crypto->in_cipher->set_decrypt_key( + session->current_crypto->in_cipher, + session->current_crypto->decryptkey, + session->current_crypto->decryptIV); + if (rc < 0) { + return (uint32_t)-1; + } + session->current_crypto->in_cipher->aead_decrypt_length( + session->current_crypto->in_cipher, source, destination, + session->current_crypto->in_cipher->lenfield_blocksize, + session->recv_seq); + } else { + rc = ssh_packet_decrypt( + session, + destination, + source, + 0, + session->current_crypto->in_cipher->blocksize); + if (rc < 0) { + return 0; + } + } + } else { + memcpy(destination, source, 8); } - } - memcpy(&decrypted,crypted,sizeof(decrypted)); - return ntohl(decrypted); + memcpy(&decrypted,destination,sizeof(decrypted)); + + return ntohl(decrypted); } -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; +/** @internal + * @brief decrypts the content of an SSH packet. + * @param[source] source packet, including the encrypted length field + * @param[start] index in the packet that was not decrypted yet. + * @param[encrypted_size] size of the encrypted data to be decrypted after start. + */ +int ssh_packet_decrypt(ssh_session session, + uint8_t *destination, + uint8_t *source, + size_t start, + size_t encrypted_size) +{ + struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher; + int rc; + + if (encrypted_size <= 0) { + return SSH_ERROR; + } - assert(len); + if (encrypted_size % session->current_crypto->in_cipher->blocksize != 0) { + ssh_set_error(session, + SSH_FATAL, + "Cryptographic functions must be used on multiple of " + "blocksize (received %" PRIdS ")", + encrypted_size); + return SSH_ERROR; + } - if(len % session->current_crypto->in_cipher->blocksize != 0){ - ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len); - return SSH_ERROR; - } - out = malloc(len); - if (out == NULL) { - return -1; - } + rc = crypto->set_decrypt_key(crypto, + session->current_crypto->decryptkey, + session->current_crypto->decryptIV); + if (rc < 0) { + return -1; + } - crypto->decrypt(crypto,data,out,len); + if (crypto->aead_decrypt != NULL) { + return crypto->aead_decrypt(crypto, + source, + destination, + encrypted_size, + session->recv_seq); + } else { + crypto->decrypt(crypto, source + start, destination, encrypted_size); + } - memcpy(data,out,len); - explicit_bzero(out, len); - SAFE_FREE(out); - return 0; + return 0; } unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) { @@ -159,13 +216,21 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) * @return 0 if hmac and mac are equal, < 0 if not or an error * occurred. */ -int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer, - unsigned char *mac, enum ssh_hmac_e type) { +int ssh_packet_hmac_verify(ssh_session session, + ssh_buffer buffer, + uint8_t *mac, + enum ssh_hmac_e type) +{ unsigned char hmacbuf[DIGEST_MAX_LEN] = {0}; HMACCTX ctx; unsigned int len; uint32_t seq; + /* AEAD type have no mac checking */ + if (type == SSH_HMAC_AEAD_POLY1305) { + return SSH_OK; + } + ctx = hmac_init(session->current_crypto->decryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { return -1; @@ -188,5 +253,3 @@ int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer, return -1; } - -/* vim: set ts=2 sw=2 et cindent: */ |