diff packet.c @ 1672:3a97f14c0235

Add Chacha20-Poly1305, AES128-GCM and AES256-GCM support (#93) * Add Chacha20-Poly1305 authenticated encryption * Add general AEAD approach. * Add [email protected] algo using LibTomCrypt chacha and poly1305 routines. Chacha20-Poly1305 is generally faster than AES256 on CPU w/o dedicated AES instructions, having the same key size. Compiling in will add ~5,5kB to binary size on x86-64. function old new delta chacha_crypt - 1397 +1397 _poly1305_block - 608 +608 poly1305_done - 595 +595 dropbear_chachapoly_crypt - 457 +457 .rodata 26976 27392 +416 poly1305_process - 290 +290 poly1305_init - 221 +221 chacha_setup - 218 +218 encrypt_packet 1068 1270 +202 dropbear_chachapoly_getlength - 147 +147 decrypt_packet 756 897 +141 chacha_ivctr64 - 137 +137 read_packet 543 637 +94 dropbear_chachapoly_start - 94 +94 read_kex_algos 792 880 +88 chacha_keystream - 69 +69 dropbear_mode_chachapoly - 48 +48 sshciphers 280 320 +40 dropbear_mode_none 24 48 +24 dropbear_mode_ctr 24 48 +24 dropbear_mode_cbc 24 48 +24 dropbear_chachapoly_mac - 24 +24 dropbear_chachapoly - 24 +24 gen_new_keys 848 854 +6 ------------------------------------------------------------------------------ (add/remove: 14/0 grow/shrink: 10/0 up/down: 5388/0) Total: 5388 bytes * Add AES128-GCM and AES256-GCM authenticated encryption * Add general AES-GCM mode. * Add [email protected] and [email protected] algo using LibTomCrypt gcm routines. AES-GCM is combination of AES CTR mode and GHASH, slower than AES-CTR on CPU w/o dedicated AES/GHASH instructions therefore disabled by default. Compiling in will add ~6kB to binary size on x86-64. function old new delta gcm_process - 1060 +1060 .rodata 26976 27808 +832 gcm_gf_mult - 820 +820 gcm_add_aad - 660 +660 gcm_shift_table - 512 +512 gcm_done - 471 +471 gcm_add_iv - 384 +384 gcm_init - 347 +347 dropbear_gcm_crypt - 309 +309 encrypt_packet 1068 1270 +202 decrypt_packet 756 897 +141 gcm_reset - 118 +118 read_packet 543 637 +94 read_kex_algos 792 880 +88 sshciphers 280 360 +80 gcm_mult_h - 80 +80 dropbear_gcm_start - 62 +62 dropbear_mode_gcm - 48 +48 dropbear_mode_none 24 48 +24 dropbear_mode_ctr 24 48 +24 dropbear_mode_cbc 24 48 +24 dropbear_ghash - 24 +24 dropbear_gcm_getlength - 24 +24 gen_new_keys 848 854 +6 ------------------------------------------------------------------------------ (add/remove: 14/0 grow/shrink: 10/0 up/down: 6434/0) Total: 6434 bytes
author Vladislav Grishenko <themiron@users.noreply.github.com>
date Mon, 25 May 2020 20:50:25 +0500
parents c4bf28ccab97
children 3b9b427925a0
line wrap: on
line diff
--- a/packet.c	Mon May 25 18:28:27 2020 +0500
+++ b/packet.c	Mon May 25 20:50:25 2020 +0500
@@ -215,7 +215,7 @@
 
 	unsigned int maxlen;
 	int slen;
-	unsigned int len;
+	unsigned int len, plen;
 	unsigned int blocksize;
 	unsigned int macsize;
 
@@ -254,21 +254,35 @@
 	/* now we have the first block, need to get packet length, so we decrypt
 	 * the first block (only need first 4 bytes) */
 	buf_setpos(ses.readbuf, 0);
-	if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), 
-				buf_getwriteptr(ses.readbuf, blocksize),
-				blocksize,
-				&ses.keys->recv.cipher_state) != CRYPT_OK) {
-		dropbear_exit("Error decrypting");
+#if DROPBEAR_AEAD_MODE
+	if (ses.keys->recv.crypt_mode->aead_crypt) {
+		if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq,
+					buf_getptr(ses.readbuf, blocksize), &plen,
+					blocksize,
+					&ses.keys->recv.cipher_state) != CRYPT_OK) {
+			dropbear_exit("Error decrypting");
+		}
+		len = plen + 4 + macsize;
+	} else
+#endif
+	{
+		if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), 
+					buf_getwriteptr(ses.readbuf, blocksize),
+					blocksize,
+					&ses.keys->recv.cipher_state) != CRYPT_OK) {
+			dropbear_exit("Error decrypting");
+		}
+		plen = buf_getint(ses.readbuf) + 4;
+		len = plen + macsize;
 	}
-	len = buf_getint(ses.readbuf) + 4 + macsize;
 
 	TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
 
 
 	/* check packet length */
 	if ((len > RECV_MAX_PACKET_LEN) ||
-		(len < MIN_PACKET_LEN + macsize) ||
-		((len - macsize) % blocksize != 0)) {
+		(plen < blocksize) ||
+		(plen % blocksize != 0)) {
 		dropbear_exit("Integrity error (bad packet size %u)", len);
 	}
 
@@ -294,23 +308,42 @@
 
 	ses.kexstate.datarecv += ses.readbuf->len;
 
-	/* we've already decrypted the first blocksize in read_packet_init */
-	buf_setpos(ses.readbuf, blocksize);
+#if DROPBEAR_AEAD_MODE
+	if (ses.keys->recv.crypt_mode->aead_crypt) {
+		/* first blocksize is not decrypted yet */
+		buf_setpos(ses.readbuf, 0);
 
-	/* decrypt it in-place */
-	len = ses.readbuf->len - macsize - ses.readbuf->pos;
-	if (ses.keys->recv.crypt_mode->decrypt(
-				buf_getptr(ses.readbuf, len), 
-				buf_getwriteptr(ses.readbuf, len),
-				len,
-				&ses.keys->recv.cipher_state) != CRYPT_OK) {
-		dropbear_exit("Error decrypting");
-	}
-	buf_incrpos(ses.readbuf, len);
+		/* decrypt it in-place */
+		len = ses.readbuf->len - macsize - ses.readbuf->pos;
+		if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq,
+					buf_getptr(ses.readbuf, len + macsize),
+					buf_getwriteptr(ses.readbuf, len),
+					len, macsize,
+					&ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) {
+			dropbear_exit("Error decrypting");
+		}
+		buf_incrpos(ses.readbuf, len);
+	} else
+#endif
+	{
+		/* we've already decrypted the first blocksize in read_packet_init */
+		buf_setpos(ses.readbuf, blocksize);
 
-	/* check the hmac */
-	if (checkmac() != DROPBEAR_SUCCESS) {
-		dropbear_exit("Integrity error");
+		/* decrypt it in-place */
+		len = ses.readbuf->len - macsize - ses.readbuf->pos;
+		if (ses.keys->recv.crypt_mode->decrypt(
+					buf_getptr(ses.readbuf, len), 
+					buf_getwriteptr(ses.readbuf, len),
+					len,
+					&ses.keys->recv.cipher_state) != CRYPT_OK) {
+			dropbear_exit("Error decrypting");
+		}
+		buf_incrpos(ses.readbuf, len);
+
+		/* check the hmac */
+		if (checkmac() != DROPBEAR_SUCCESS) {
+			dropbear_exit("Integrity error");
+		}
 	}
 
 	/* get padding length */
@@ -557,9 +590,16 @@
 	buf_setpos(ses.writepayload, 0);
 	buf_setlen(ses.writepayload, 0);
 
-	/* length of padding - packet length must be a multiple of blocksize,
-	 * with a minimum of 4 bytes of padding */
-	padlen = blocksize - (writebuf->len) % blocksize;
+	/* length of padding - packet length excluding the packetlength uint32
+	 * field in aead mode must be a multiple of blocksize, with a minimum of
+	 * 4 bytes of padding */
+	len = writebuf->len;
+#if DROPBEAR_AEAD_MODE
+	if (ses.keys->trans.crypt_mode->aead_crypt) {
+		len -= 4;
+	}
+#endif
+	padlen = blocksize - len % blocksize;
 	if (padlen < 4) {
 		padlen += blocksize;
 	}
@@ -579,23 +619,42 @@
 	buf_incrlen(writebuf, padlen);
 	genrandom(buf_getptr(writebuf, padlen), padlen);
 
-	make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
+#if DROPBEAR_AEAD_MODE
+	if (ses.keys->trans.crypt_mode->aead_crypt) {
+		/* do the actual encryption, in-place */
+		buf_setpos(writebuf, 0);
+		/* encrypt it in-place*/
+		len = writebuf->len;
+		buf_incrlen(writebuf, mac_size);
+		if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq,
+					buf_getptr(writebuf, len),
+					buf_getwriteptr(writebuf, len + mac_size),
+					len, mac_size,
+					&ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) {
+			dropbear_exit("Error encrypting");
+		}
+		buf_incrpos(writebuf, len + mac_size);
+	} else
+#endif
+	{
+		make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
 
-	/* do the actual encryption, in-place */
-	buf_setpos(writebuf, 0);
-	/* encrypt it in-place*/
-	len = writebuf->len;
-	if (ses.keys->trans.crypt_mode->encrypt(
-				buf_getptr(writebuf, len),
-				buf_getwriteptr(writebuf, len),
-				len,
-				&ses.keys->trans.cipher_state) != CRYPT_OK) {
-		dropbear_exit("Error encrypting");
+		/* do the actual encryption, in-place */
+		buf_setpos(writebuf, 0);
+		/* encrypt it in-place*/
+		len = writebuf->len;
+		if (ses.keys->trans.crypt_mode->encrypt(
+					buf_getptr(writebuf, len),
+					buf_getwriteptr(writebuf, len),
+					len,
+					&ses.keys->trans.cipher_state) != CRYPT_OK) {
+			dropbear_exit("Error encrypting");
+		}
+		buf_incrpos(writebuf, len);
+
+		/* stick the MAC on it */
+		buf_putbytes(writebuf, mac_bytes, mac_size);
 	}
-	buf_incrpos(writebuf, len);
-
-	/* stick the MAC on it */
-	buf_putbytes(writebuf, mac_bytes, mac_size);
 
 	/* Update counts */
 	ses.kexstate.datatrans += writebuf->len;