Mercurial > dropbear
comparison 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 |
comparison
equal
deleted
inserted
replaced
1671:5c8913b7464c | 1672:3a97f14c0235 |
---|---|
213 * DROPBEAR_FAILURE otherwise */ | 213 * DROPBEAR_FAILURE otherwise */ |
214 static int read_packet_init() { | 214 static int read_packet_init() { |
215 | 215 |
216 unsigned int maxlen; | 216 unsigned int maxlen; |
217 int slen; | 217 int slen; |
218 unsigned int len; | 218 unsigned int len, plen; |
219 unsigned int blocksize; | 219 unsigned int blocksize; |
220 unsigned int macsize; | 220 unsigned int macsize; |
221 | 221 |
222 | 222 |
223 blocksize = ses.keys->recv.algo_crypt->blocksize; | 223 blocksize = ses.keys->recv.algo_crypt->blocksize; |
252 } | 252 } |
253 | 253 |
254 /* now we have the first block, need to get packet length, so we decrypt | 254 /* now we have the first block, need to get packet length, so we decrypt |
255 * the first block (only need first 4 bytes) */ | 255 * the first block (only need first 4 bytes) */ |
256 buf_setpos(ses.readbuf, 0); | 256 buf_setpos(ses.readbuf, 0); |
257 if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), | 257 #if DROPBEAR_AEAD_MODE |
258 buf_getwriteptr(ses.readbuf, blocksize), | 258 if (ses.keys->recv.crypt_mode->aead_crypt) { |
259 blocksize, | 259 if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq, |
260 &ses.keys->recv.cipher_state) != CRYPT_OK) { | 260 buf_getptr(ses.readbuf, blocksize), &plen, |
261 dropbear_exit("Error decrypting"); | 261 blocksize, |
262 } | 262 &ses.keys->recv.cipher_state) != CRYPT_OK) { |
263 len = buf_getint(ses.readbuf) + 4 + macsize; | 263 dropbear_exit("Error decrypting"); |
264 } | |
265 len = plen + 4 + macsize; | |
266 } else | |
267 #endif | |
268 { | |
269 if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), | |
270 buf_getwriteptr(ses.readbuf, blocksize), | |
271 blocksize, | |
272 &ses.keys->recv.cipher_state) != CRYPT_OK) { | |
273 dropbear_exit("Error decrypting"); | |
274 } | |
275 plen = buf_getint(ses.readbuf) + 4; | |
276 len = plen + macsize; | |
277 } | |
264 | 278 |
265 TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize)) | 279 TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize)) |
266 | 280 |
267 | 281 |
268 /* check packet length */ | 282 /* check packet length */ |
269 if ((len > RECV_MAX_PACKET_LEN) || | 283 if ((len > RECV_MAX_PACKET_LEN) || |
270 (len < MIN_PACKET_LEN + macsize) || | 284 (plen < blocksize) || |
271 ((len - macsize) % blocksize != 0)) { | 285 (plen % blocksize != 0)) { |
272 dropbear_exit("Integrity error (bad packet size %u)", len); | 286 dropbear_exit("Integrity error (bad packet size %u)", len); |
273 } | 287 } |
274 | 288 |
275 if (len > ses.readbuf->size) { | 289 if (len > ses.readbuf->size) { |
276 ses.readbuf = buf_resize(ses.readbuf, len); | 290 ses.readbuf = buf_resize(ses.readbuf, len); |
292 blocksize = ses.keys->recv.algo_crypt->blocksize; | 306 blocksize = ses.keys->recv.algo_crypt->blocksize; |
293 macsize = ses.keys->recv.algo_mac->hashsize; | 307 macsize = ses.keys->recv.algo_mac->hashsize; |
294 | 308 |
295 ses.kexstate.datarecv += ses.readbuf->len; | 309 ses.kexstate.datarecv += ses.readbuf->len; |
296 | 310 |
297 /* we've already decrypted the first blocksize in read_packet_init */ | 311 #if DROPBEAR_AEAD_MODE |
298 buf_setpos(ses.readbuf, blocksize); | 312 if (ses.keys->recv.crypt_mode->aead_crypt) { |
299 | 313 /* first blocksize is not decrypted yet */ |
300 /* decrypt it in-place */ | 314 buf_setpos(ses.readbuf, 0); |
301 len = ses.readbuf->len - macsize - ses.readbuf->pos; | 315 |
302 if (ses.keys->recv.crypt_mode->decrypt( | 316 /* decrypt it in-place */ |
303 buf_getptr(ses.readbuf, len), | 317 len = ses.readbuf->len - macsize - ses.readbuf->pos; |
304 buf_getwriteptr(ses.readbuf, len), | 318 if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq, |
305 len, | 319 buf_getptr(ses.readbuf, len + macsize), |
306 &ses.keys->recv.cipher_state) != CRYPT_OK) { | 320 buf_getwriteptr(ses.readbuf, len), |
307 dropbear_exit("Error decrypting"); | 321 len, macsize, |
308 } | 322 &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) { |
309 buf_incrpos(ses.readbuf, len); | 323 dropbear_exit("Error decrypting"); |
310 | 324 } |
311 /* check the hmac */ | 325 buf_incrpos(ses.readbuf, len); |
312 if (checkmac() != DROPBEAR_SUCCESS) { | 326 } else |
313 dropbear_exit("Integrity error"); | 327 #endif |
328 { | |
329 /* we've already decrypted the first blocksize in read_packet_init */ | |
330 buf_setpos(ses.readbuf, blocksize); | |
331 | |
332 /* decrypt it in-place */ | |
333 len = ses.readbuf->len - macsize - ses.readbuf->pos; | |
334 if (ses.keys->recv.crypt_mode->decrypt( | |
335 buf_getptr(ses.readbuf, len), | |
336 buf_getwriteptr(ses.readbuf, len), | |
337 len, | |
338 &ses.keys->recv.cipher_state) != CRYPT_OK) { | |
339 dropbear_exit("Error decrypting"); | |
340 } | |
341 buf_incrpos(ses.readbuf, len); | |
342 | |
343 /* check the hmac */ | |
344 if (checkmac() != DROPBEAR_SUCCESS) { | |
345 dropbear_exit("Integrity error"); | |
346 } | |
314 } | 347 } |
315 | 348 |
316 /* get padding length */ | 349 /* get padding length */ |
317 buf_setpos(ses.readbuf, PACKET_PADDING_OFF); | 350 buf_setpos(ses.readbuf, PACKET_PADDING_OFF); |
318 padlen = buf_getbyte(ses.readbuf); | 351 padlen = buf_getbyte(ses.readbuf); |
555 | 588 |
556 /* finished with payload */ | 589 /* finished with payload */ |
557 buf_setpos(ses.writepayload, 0); | 590 buf_setpos(ses.writepayload, 0); |
558 buf_setlen(ses.writepayload, 0); | 591 buf_setlen(ses.writepayload, 0); |
559 | 592 |
560 /* length of padding - packet length must be a multiple of blocksize, | 593 /* length of padding - packet length excluding the packetlength uint32 |
561 * with a minimum of 4 bytes of padding */ | 594 * field in aead mode must be a multiple of blocksize, with a minimum of |
562 padlen = blocksize - (writebuf->len) % blocksize; | 595 * 4 bytes of padding */ |
596 len = writebuf->len; | |
597 #if DROPBEAR_AEAD_MODE | |
598 if (ses.keys->trans.crypt_mode->aead_crypt) { | |
599 len -= 4; | |
600 } | |
601 #endif | |
602 padlen = blocksize - len % blocksize; | |
563 if (padlen < 4) { | 603 if (padlen < 4) { |
564 padlen += blocksize; | 604 padlen += blocksize; |
565 } | 605 } |
566 /* check for min packet length */ | 606 /* check for min packet length */ |
567 if (writebuf->len + padlen < MIN_PACKET_LEN) { | 607 if (writebuf->len + padlen < MIN_PACKET_LEN) { |
577 /* actual padding */ | 617 /* actual padding */ |
578 buf_setpos(writebuf, writebuf->len); | 618 buf_setpos(writebuf, writebuf->len); |
579 buf_incrlen(writebuf, padlen); | 619 buf_incrlen(writebuf, padlen); |
580 genrandom(buf_getptr(writebuf, padlen), padlen); | 620 genrandom(buf_getptr(writebuf, padlen), padlen); |
581 | 621 |
582 make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); | 622 #if DROPBEAR_AEAD_MODE |
583 | 623 if (ses.keys->trans.crypt_mode->aead_crypt) { |
584 /* do the actual encryption, in-place */ | 624 /* do the actual encryption, in-place */ |
585 buf_setpos(writebuf, 0); | 625 buf_setpos(writebuf, 0); |
586 /* encrypt it in-place*/ | 626 /* encrypt it in-place*/ |
587 len = writebuf->len; | 627 len = writebuf->len; |
588 if (ses.keys->trans.crypt_mode->encrypt( | 628 buf_incrlen(writebuf, mac_size); |
589 buf_getptr(writebuf, len), | 629 if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq, |
590 buf_getwriteptr(writebuf, len), | 630 buf_getptr(writebuf, len), |
591 len, | 631 buf_getwriteptr(writebuf, len + mac_size), |
592 &ses.keys->trans.cipher_state) != CRYPT_OK) { | 632 len, mac_size, |
593 dropbear_exit("Error encrypting"); | 633 &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) { |
594 } | 634 dropbear_exit("Error encrypting"); |
595 buf_incrpos(writebuf, len); | 635 } |
596 | 636 buf_incrpos(writebuf, len + mac_size); |
597 /* stick the MAC on it */ | 637 } else |
598 buf_putbytes(writebuf, mac_bytes, mac_size); | 638 #endif |
639 { | |
640 make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); | |
641 | |
642 /* do the actual encryption, in-place */ | |
643 buf_setpos(writebuf, 0); | |
644 /* encrypt it in-place*/ | |
645 len = writebuf->len; | |
646 if (ses.keys->trans.crypt_mode->encrypt( | |
647 buf_getptr(writebuf, len), | |
648 buf_getwriteptr(writebuf, len), | |
649 len, | |
650 &ses.keys->trans.cipher_state) != CRYPT_OK) { | |
651 dropbear_exit("Error encrypting"); | |
652 } | |
653 buf_incrpos(writebuf, len); | |
654 | |
655 /* stick the MAC on it */ | |
656 buf_putbytes(writebuf, mac_bytes, mac_size); | |
657 } | |
599 | 658 |
600 /* Update counts */ | 659 /* Update counts */ |
601 ses.kexstate.datatrans += writebuf->len; | 660 ses.kexstate.datatrans += writebuf->len; |
602 | 661 |
603 writebuf_enqueue(writebuf); | 662 writebuf_enqueue(writebuf); |