diff --git a/bip39.c b/bip39.c index fe0d4f121..019259386 100644 --- a/bip39.c +++ b/bip39.c @@ -152,7 +152,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed memcpy(salt, "mnemonic", 8); memcpy(salt + 8, passphrase, saltlen); saltlen += 8; - pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); } const char **mnemonic_wordlist(void) diff --git a/pbkdf2.c b/pbkdf2.c index 02699a0e9..2271f997c 100644 --- a/pbkdf2.c +++ b/pbkdf2.c @@ -25,11 +25,42 @@ #include "pbkdf2.h" #include "hmac.h" -#define HMACFUNC hmac_sha512 -#define HMACLEN (512/8) +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +{ + const uint32_t HMACLEN = 256/8; + uint32_t i, j, k; + uint8_t f[HMACLEN], g[HMACLEN]; + uint32_t blocks = keylen / HMACLEN; + if (keylen & (HMACLEN - 1)) { + blocks++; + } + for (i = 1; i <= blocks; i++) { + salt[saltlen ] = (i >> 24) & 0xFF; + salt[saltlen + 1] = (i >> 16) & 0xFF; + salt[saltlen + 2] = (i >> 8) & 0xFF; + salt[saltlen + 3] = i & 0xFF; + hmac_sha256(pass, passlen, salt, saltlen + 4, g); + memcpy(f, g, HMACLEN); + for (j = 1; j < iterations; j++) { + hmac_sha256(pass, passlen, g, HMACLEN, g); + for (k = 0; k < HMACLEN; k++) { + f[k] ^= g[k]; + } + if (progress_callback && (j % 256 == 255)) { + progress_callback(j + 1, iterations); + } + } + if (i == blocks && (keylen & (HMACLEN - 1))) { + memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); + } else { + memcpy(key + HMACLEN * (i - 1), f, HMACLEN); + } + } +} -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)) { + const uint32_t HMACLEN = 512/8; uint32_t i, j, k; uint8_t f[HMACLEN], g[HMACLEN]; uint32_t blocks = keylen / HMACLEN; @@ -41,18 +72,18 @@ void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32 salt[saltlen + 1] = (i >> 16) & 0xFF; salt[saltlen + 2] = (i >> 8) & 0xFF; salt[saltlen + 3] = i & 0xFF; - HMACFUNC(pass, passlen, salt, saltlen + 4, g); + hmac_sha512(pass, passlen, salt, saltlen + 4, g); memcpy(f, g, HMACLEN); for (j = 1; j < iterations; j++) { - HMACFUNC(pass, passlen, g, HMACLEN, g); + hmac_sha512(pass, passlen, g, HMACLEN, g); for (k = 0; k < HMACLEN; k++) { f[k] ^= g[k]; } - if (progress_callback && j % 256 == 255) { + if (progress_callback && (j % 256 == 255)) { progress_callback(j + 1, iterations); } } - if (i == blocks - 1 && (keylen & (HMACLEN - 1))) { + if (i == blocks && (keylen & (HMACLEN - 1))) { memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); } else { memcpy(key + HMACLEN * (i - 1), f, HMACLEN); diff --git a/pbkdf2.h b/pbkdf2.h index 8e88955a8..6fe09788b 100644 --- a/pbkdf2.h +++ b/pbkdf2.h @@ -27,6 +27,8 @@ #include // salt needs to have 4 extra bytes available beyond saltlen -void pbkdf2(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); +// salt needs to have 4 extra bytes available beyond saltlen +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, uint32_t total)); #endif diff --git a/tests.c b/tests.c index 8dc7c8d94..dc72b373d 100644 --- a/tests.c +++ b/tests.c @@ -587,25 +587,48 @@ START_TEST(test_aes) } END_TEST +// test vectors from https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors +START_TEST(test_pbkdf2_hmac_sha256) +{ + uint8_t k[40], s[40]; + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 1, k, 32, 0); + ck_assert_mem_eq(k, fromhex("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), 32); + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 2, k, 32, 0); + ck_assert_mem_eq(k, fromhex("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), 32); + + strcpy((char *)s, "salt"); + pbkdf2_hmac_sha256((uint8_t *)"password", 8, s, 4, 4096, k, 32, 0); + ck_assert_mem_eq(k, fromhex("c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"), 32); + + strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); + pbkdf2_hmac_sha256((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + ck_assert_mem_eq(k, fromhex("348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9"), 40); +} +END_TEST + // test vectors from http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors -START_TEST(test_pbkdf2) +START_TEST(test_pbkdf2_hmac_sha512) { - uint8_t k[64], s[64]; + uint8_t k[64], s[40]; strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 1, k, 64, 0); ck_assert_mem_eq(k, fromhex("867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 2, k, 64, 0); ck_assert_mem_eq(k, fromhex("e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e"), 64); strcpy((char *)s, "salt"); - pbkdf2((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"password", 8, s, 4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5"), 64); strcpy((char *)s, "saltSALTsaltSALTsaltSALTsaltSALTsalt"); - pbkdf2((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); + pbkdf2_hmac_sha512((uint8_t *)"passwordPASSWORDpassword", 3*8, s, 9*4, 4096, k, 64, 0); ck_assert_mem_eq(k, fromhex("8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8"), 64); } END_TEST @@ -1074,7 +1097,8 @@ Suite *test_suite(void) suite_add_tcase(s, tc); tc = tcase_create("pbkdf2"); - tcase_add_test(tc, test_pbkdf2); + tcase_add_test(tc, test_pbkdf2_hmac_sha256); + tcase_add_test(tc, test_pbkdf2_hmac_sha512); suite_add_tcase(s, tc); tc = tcase_create("bip39");