Mercurial > dropbear
view libtomcrypt/src/misc/pkcs5/pkcs_5_1.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 | 6dba84798cd5 |
children |
line wrap: on
line source
/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #include "tomcrypt.h" /** @file pkcs_5_1.c PKCS #5, Algorithm #1, Tom St Denis */ #ifdef LTC_PKCS_5 /** Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode. PKCS#5 v1 specifies that the output key length can be no larger than the hash output length. OpenSSL unilaterally extended that by repeating the hash process on a block-by-block basis for as long as needed to make bigger keys. If you want to be compatible with KDF for e.g. "openssl enc", you'll want that. If you want strict PKCS behavior, turn openssl_compat off. Or (more likely), use one of the convenience functions below. @param password The password (or key) @param password_len The length of the password (octet) @param salt The salt (or nonce) which is 8 octets long @param iteration_count The PKCS #5 v1 iteration count @param hash_idx The index of the hash desired @param out [out] The destination for this algorithm @param outlen [in/out] The max size and resulting size of the algorithm output @param openssl_compat [in] Whether or not to grow the key to the buffer size ala OpenSSL @return CRYPT_OK if successful */ static int _pkcs_5_alg1_common(const unsigned char *password, unsigned long password_len, const unsigned char *salt, int iteration_count, int hash_idx, unsigned char *out, unsigned long *outlen, int openssl_compat) { int err; unsigned long x; hash_state *md; unsigned char *buf; /* Storage vars in case we need to support > hashsize (OpenSSL compat) */ unsigned long block = 0, iter; /* How many bytes to put in the outbut buffer (convenience calc) */ unsigned long outidx = 0, nb = 0; LTC_ARGCHK(password != NULL); LTC_ARGCHK(salt != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); /* test hash IDX */ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; } /* allocate memory */ md = XMALLOC(sizeof(hash_state)); buf = XMALLOC(MAXBLOCKSIZE); if (md == NULL || buf == NULL) { if (md != NULL) { XFREE(md); } if (buf != NULL) { XFREE(buf); } return CRYPT_MEM; } while(block * hash_descriptor[hash_idx].hashsize < *outlen) { /* hash initial (maybe previous hash) + password + salt */ if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) { goto LBL_ERR; } /* in OpenSSL mode, we first hash the previous result for blocks 2-n */ if (openssl_compat && block) { if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) { goto LBL_ERR; } } if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) { goto LBL_ERR; } if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) { goto LBL_ERR; } if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) { goto LBL_ERR; } iter = iteration_count; while (--iter) { /* code goes here. */ x = MAXBLOCKSIZE; if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) { goto LBL_ERR; } } /* limit the size of the copy to however many bytes we have left in the output buffer (and how many bytes we have to copy) */ outidx = block*hash_descriptor[hash_idx].hashsize; nb = hash_descriptor[hash_idx].hashsize; if(outidx+nb > *outlen) nb = *outlen - outidx; if(nb > 0) XMEMCPY(out+outidx, buf, nb); block++; if (!openssl_compat) break; } /* In strict mode, we always return the hashsize, in compat we filled it as much as was requested, so we leave it alone. */ if(!openssl_compat) *outlen = hash_descriptor[hash_idx].hashsize; err = CRYPT_OK; LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(buf, MAXBLOCKSIZE); zeromem(md, sizeof(hash_state)); #endif XFREE(buf); XFREE(md); return err; } /** Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension) @param password The password (or key) @param password_len The length of the password (octet) @param salt The salt (or nonce) which is 8 octets long @param iteration_count The PKCS #5 v1 iteration count @param hash_idx The index of the hash desired @param out [out] The destination for this algorithm @param outlen [in/out] The max size and resulting size of the algorithm output @return CRYPT_OK if successful */ int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, const unsigned char *salt, int iteration_count, int hash_idx, unsigned char *out, unsigned long *outlen) { return _pkcs_5_alg1_common(password, password_len, salt, iteration_count, hash_idx, out, outlen, 0); } /** Execute PKCS #5 v1 - OpenSSL-extension-compatible mode Use this one if you need to derive keys as "openssl enc" does by default. OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1. @param password The password (or key) @param password_len The length of the password (octet) @param salt The salt (or nonce) which is 8 octets long @param iteration_count The PKCS #5 v1 iteration count @param hash_idx The index of the hash desired @param out [out] The destination for this algorithm @param outlen [in/out] The max size and resulting size of the algorithm output @return CRYPT_OK if successful */ int pkcs_5_alg1_openssl(const unsigned char *password, unsigned long password_len, const unsigned char *salt, int iteration_count, int hash_idx, unsigned char *out, unsigned long *outlen) { return _pkcs_5_alg1_common(password, password_len, salt, iteration_count, hash_idx, out, outlen, 1); } #endif /* ref: $Format:%D$ */ /* git commit: $Format:%H$ */ /* commit time: $Format:%ai$ */