diff options
Diffstat (limited to 'libtomcrypt/src/misc/pkcs5')
-rw-r--r-- | libtomcrypt/src/misc/pkcs5/pkcs_5_1.c | 161 | ||||
-rw-r--r-- | libtomcrypt/src/misc/pkcs5/pkcs_5_2.c | 24 | ||||
-rw-r--r-- | libtomcrypt/src/misc/pkcs5/pkcs_5_test.c | 231 |
3 files changed, 363 insertions, 53 deletions
diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c index 519e7aa..10325de 100644 --- a/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c +++ b/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c @@ -5,36 +5,51 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ -#include <tomcrypt.h> +#include "tomcrypt.h" -/** +/** @file pkcs_5_1.c - LTC_PKCS #5, Algorithm #1, Tom St Denis + PKCS #5, Algorithm #1, Tom St Denis */ #ifdef LTC_PKCS_5 /** - Execute LTC_PKCS #5 v1 + 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 LTC_PKCS #5 v1 iteration count + @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 */ -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) +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); @@ -53,42 +68,64 @@ int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, if (md != NULL) { XFREE(md); } - if (buf != NULL) { + if (buf != NULL) { XFREE(buf); } return CRYPT_MEM; - } - - /* hash initial password + salt */ - if ((err = hash_descriptor[hash_idx].init(md)) != 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; } - while (--iteration_count) { - /* code goes here. */ - x = MAXBLOCKSIZE; - if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) { - goto LBL_ERR; + 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); - /* copy upto outlen bytes */ - for (x = 0; x < hash_descriptor[hash_idx].hashsize && x < *outlen; x++) { - out[x] = buf[x]; + block++; + if (!openssl_compat) + break; } - *outlen = x; + /* 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 +#ifdef LTC_CLEAN_STACK zeromem(buf, MAXBLOCKSIZE); zeromem(md, sizeof(hash_state)); #endif @@ -99,8 +136,52 @@ LBL_ERR: 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 -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c index 0d76d62..2265bcb 100644 --- a/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c +++ b/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c @@ -5,30 +5,28 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ -#include <tomcrypt.h> +#include "tomcrypt.h" -/** +/** @file pkcs_5_2.c - LTC_PKCS #5, Algorithm #2, Tom St Denis + PKCS #5, Algorithm #2, Tom St Denis */ #ifdef LTC_PKCS_5 /** - Execute LTC_PKCS #5 v2 + Execute PKCS #5 v2 @param password The input password (or key) @param password_len The length of the password (octets) @param salt The salt (or nonce) @param salt_len The length of the salt (octets) - @param iteration_count # of iterations desired for LTC_PKCS #5 v2 [read specs for more] + @param iteration_count # of iterations desired for PKCS #5 v2 [read specs for more] @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_alg2(const unsigned char *password, unsigned long password_len, +int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, const unsigned char *salt, unsigned long salt_len, int iteration_count, int hash_idx, unsigned char *out, unsigned long *outlen) @@ -69,13 +67,13 @@ int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, while (left != 0) { /* process block number blkno */ zeromem(buf[0], MAXBLOCKSIZE*2); - + /* store current block number and increment for next pass */ STORE32H(blkno, buf[1]); ++blkno; /* get PRF(P, S||int(blkno)) */ - if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) { + if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) { goto LBL_ERR; } if ((err = hmac_process(hmac, salt, salt_len)) != CRYPT_OK) { @@ -124,6 +122,6 @@ LBL_ERR: #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_test.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_test.c new file mode 100644 index 0000000..f6e413b --- /dev/null +++ b/libtomcrypt/src/misc/pkcs5/pkcs_5_test.c @@ -0,0 +1,231 @@ +/* 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 hkdf_test.c + PKCS #5 support, self-test, Steffen Jaeckel +*/ + +#ifdef LTC_PKCS_5 + +/* + TEST CASES SOURCE: + +Internet Engineering Task Force (IETF) S. Josefsson +Request for Comments: 6070 SJD AB +Category: Informational January 2011 +ISSN: 2070-1721 +*/ + +/** + PKCS #5 self-test + @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled. +*/ +int pkcs_5_test (void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + + typedef struct { + const char* P; + unsigned long P_len; + const char* S; + unsigned long S_len; + int c; + unsigned long dkLen; + unsigned char DK[40]; + } case_item; + + static const case_item cases_5_2[] = { + { + "password", + 8, + "salt", + 4, + 1, + 20, + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 } + }, + { + "password", + 8, + "salt", + 4, + 2, + 20, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 } + }, +#ifdef LTC_TEST_EXT + { + "password", + 8, + "salt", + 4, + 4096, + 20, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 } + }, + { + "password", + 8, + "salt", + 4, + 16777216, + 20, + { 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4, + 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c, + 0x26, 0x34, 0xe9, 0x84 } + }, + { + "passwordPASSWORDpassword", + 25, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + 36, + 4096, + 25, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 } + }, + { + "pass\0word", + 9, + "sa\0lt", + 5, + 4096, + 16, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 } + }, +#endif /* LTC_TEST_EXT */ + }; + + static const case_item cases_5_1[] = { + { + "password", + 8, + "saltsalt", /* must be 8 octects */ + 8, /* ignored by alg1 */ + 1, + 20, + { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, + 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 } + }, + }; + + static const case_item cases_5_1o[] = { + { + "password", + 8, + "saltsalt", /* must be 8 octects */ + 8, /* ignored by alg1_openssl */ + 1, + 20, + { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, + 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 } + + }, + { + "password", + 8, + "saltsalt", /* must be 8 octects */ + 8, /* ignored by alg1_openssl */ + 1, + 30, + { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, + 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44, + 0xf0, 0xbf, 0xf4, 0xc1, 0x2c, 0xf3, 0x59, 0x6f, 0xc0, 0x0b } + + } + }; + + unsigned char DK[40]; + unsigned long dkLen; + int i, err; + int tested=0, failed=0; + int hash = find_hash("sha1"); + if (hash == -1) + { +#ifdef LTC_TEST_DBG + printf("PKCS#5 test failed: 'sha1' hash not found\n"); +#endif + return CRYPT_ERROR; + } + + /* testing alg 2 */ + for(i=0; i < (int)(sizeof(cases_5_2) / sizeof(cases_5_2[0])); i++) { + ++tested; + dkLen = cases_5_2[i].dkLen; + if((err = pkcs_5_alg2((unsigned char*)cases_5_2[i].P, cases_5_2[i].P_len, + (unsigned char*)cases_5_2[i].S, cases_5_2[i].S_len, + cases_5_2[i].c, hash, + DK, &dkLen)) != CRYPT_OK) { +#ifdef LTC_TEST_DBG + printf("\npkcs_5_alg2() #%d: Failed/1 (%s)\n", i, error_to_string(err)); +#endif + ++failed; + } + else if (compare_testvector(DK, dkLen, cases_5_2[i].DK, cases_5_2[i].dkLen, "PKCS#5_2", i)) { + ++failed; + } + } + + /* testing alg 1 */ + for(i=0; i < (int)(sizeof(cases_5_1) / sizeof(case_item)); i++, tested++) { + dkLen = cases_5_1[i].dkLen; + if((err = pkcs_5_alg1((unsigned char*)cases_5_1[i].P, cases_5_1[i].P_len, + (unsigned char*)cases_5_1[i].S, + cases_5_1[i].c, hash, + DK, &dkLen)) != CRYPT_OK) { +#ifdef LTC_TEST_DBG + printf("\npkcs_5_alg1() #%d: Failed/1 (%s)\n", i, error_to_string(err)); +#endif + ++failed; + } + else if (compare_testvector(DK, dkLen, cases_5_1[i].DK, cases_5_1[i].dkLen, "PKCS#5_1", i)) { + ++failed; + } + } + + /* testing alg 1_openssl */ + for(i = 0; i < (int)(sizeof(cases_5_1o) / sizeof(cases_5_1o[0])); i++, tested++) { + dkLen = cases_5_1o[i].dkLen; + if ((err = pkcs_5_alg1_openssl((unsigned char*)cases_5_1o[i].P, cases_5_1o[i].P_len, + (unsigned char*)cases_5_1o[i].S, + cases_5_1o[i].c, hash, + DK, &dkLen)) != CRYPT_OK) { +#ifdef LTC_TEST_DBG + printf("\npkcs_5_alg1_openssl() #%d: Failed/1 (%s)\n", i, error_to_string(err)); +#endif + ++failed; + } + else if (compare_testvector(DK, dkLen, cases_5_1o[i].DK, cases_5_1o[i].dkLen, "PKCS#5_1o", i)) { + ++failed; + } + } + + return (failed != 0) ? CRYPT_FAIL_TESTVECTOR : CRYPT_OK; + #endif +} + +#endif + + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ |