diff --git a/include/gmssl/pbkdf2.h b/include/gmssl/pbkdf2.h index 06233b27..2b26b086 100644 --- a/include/gmssl/pbkdf2.h +++ b/include/gmssl/pbkdf2.h @@ -29,11 +29,7 @@ extern "C" { #define PBKDF2_DEFAULT_SALT_SIZE 8 -int pbkdf2_genkey(const DIGEST *digest, - const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, size_t iter, - size_t outlen, uint8_t *out); - -int pbkdf2_hmac_sm3_genkey( +int pbkdf2_hmac_genkey(const DIGEST *digest, const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, size_t iter, size_t outlen, uint8_t *out); diff --git a/src/pbkdf2.c b/src/pbkdf2.c new file mode 100644 index 00000000..6f75a0f1 --- /dev/null +++ b/src/pbkdf2.c @@ -0,0 +1,112 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include + + +int pbkdf2_hmac_genkey(const DIGEST *digest, + const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, + size_t iter, size_t outlen, uint8_t *out) +{ + int ret = -1; + HMAC_CTX ctx; + HMAC_CTX ctx_tmpl; + uint8_t iter_be[4]; + uint8_t tmp_block[DIGEST_MAX_SIZE]; + uint8_t key_block[DIGEST_MAX_SIZE]; + uint32_t block_index = 1; + size_t digest_size; + size_t block_count; + + if (!digest || !iter || !outlen || !out) { + error_print(); + return -1; + } + if (digest->digest_size > HMAC_MAX_SIZE + || !digest->digest_size) { + error_print(); + return -1; + } + if (!pass && passlen) { + error_print(); + return -1; + } + if (!salt && saltlen) { + error_print(); + return -1; + } + + digest_size = digest->digest_size; + + block_count = outlen / digest_size; + if (outlen % digest_size) { + block_count++; + } + if (block_count > UINT32_MAX) { + error_print(); + return -1; + } + + if (hmac_init(&ctx_tmpl, digest, (const uint8_t *)pass, passlen) != 1) { + error_print(); + return -1; + } + + while (outlen) { + size_t maclen; + size_t i; + + PUTU32(iter_be, block_index); + block_index++; + + ctx = ctx_tmpl; + if (hmac_update(&ctx, salt, saltlen) < 0 + || hmac_update(&ctx, iter_be, sizeof(iter_be)) != 1 + || hmac_finish(&ctx, tmp_block, &maclen) != 1) { + error_print(); + goto end; + } + memcpy(key_block, tmp_block, digest_size); + + for (i = 1; i < iter; i++) { + ctx = ctx_tmpl; + if (hmac_update(&ctx, tmp_block, digest_size) != 1 + || hmac_finish(&ctx, tmp_block, &maclen) != 1) { + error_print(); + goto end; + } + memxor(key_block, tmp_block, digest_size); + } + + if (outlen < digest_size) { + memcpy(out, key_block, outlen); + out += outlen; + outlen = 0; + } else { + memcpy(out, key_block, digest_size); + out += digest_size; + outlen -= digest_size; + } + } + + ret = 1; + +end: + gmssl_secure_clear(&ctx, sizeof(ctx)); + gmssl_secure_clear(&ctx_tmpl, sizeof(ctx_tmpl)); + gmssl_secure_clear(key_block, sizeof(key_block)); + gmssl_secure_clear(tmp_block, sizeof(tmp_block)); + return ret; +} diff --git a/tests/pbkdf2test.c b/tests/pbkdf2test.c index e2c0f2a0..90778a91 100644 --- a/tests/pbkdf2test.c +++ b/tests/pbkdf2test.c @@ -111,7 +111,7 @@ static int test_pbkdf2_genkey(void) for (i = 0; i < sizeof(pbkdf2_hmac_sha1_tests)/sizeof(pbkdf2_hmac_sha1_tests[0]); i++) { hex_to_bytes(pbkdf2_hmac_sha1_tests[i].dk, strlen(pbkdf2_hmac_sha1_tests[i].dk), buf, &len); - if (pbkdf2_genkey(DIGEST_sha1(), + if (pbkdf2_hmac_genkey(DIGEST_sha1(), pbkdf2_hmac_sha1_tests[i].pass, strlen(pbkdf2_hmac_sha1_tests[i].pass), (uint8_t *)pbkdf2_hmac_sha1_tests[i].salt, strlen(pbkdf2_hmac_sha1_tests[i].salt), pbkdf2_hmac_sha1_tests[i].iter, pbkdf2_hmac_sha1_tests[i].dklen, key) != 1) {