diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2021-01-15 14:26:12 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2021-01-15 14:26:12 +0900 |
commit | 7a0da24925361a3109474d0e433511467a9e35d1 (patch) | |
tree | b27219e47e112ec4092fbece5b63a2bd09c4f9d0 /cipher/kdf.c | |
parent | 385a89e35b0b95f15b4c6e4d5482b1fc6906f7c5 (diff) | |
download | libgcrypt-7a0da24925361a3109474d0e433511467a9e35d1.tar.gz |
kdf: Add selftest.
* src/cipher-proto.h (_gcry_kdf_selftest): New.
* cipher/kdf.c (check_one, selftest_pbkdf2): New.
(_gcry_kdf_selftest): New.
* src/fips.c (run_kdf_selftests): New.
(_gcry_fips_run_selftests): Call run_kdf_selftests.
--
Original work was libgcrypt-1.8.5-kdf-selftest.patch from Red Hat.
API style of check_one function follows the one in mac-hmac.c and
mac-cmac.c, which originates cipher/hmac-tests.c of libgcrypt 1.8
(copyrighted by Free Software Foundation, Inc., in 2008).
Covering the test vectors of original work, as an initial merge,
I include test vectors from tests/t-kdf.c, since PBKDF2 is defined
in RFC-6070 with those vectors.
Simo Sorce addressed about SHA1 deprecation. I marked the test
vectors with USE_SHA1.
GnuPG-bug-id: 5182
Co-authored-by: Tomáš Mráz <tm@t8m.info>
Suggested-by: Simo Sorce <simo@redhat.com>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'cipher/kdf.c')
-rw-r--r-- | cipher/kdf.c | 197 |
1 files changed, 196 insertions, 1 deletions
diff --git a/cipher/kdf.c b/cipher/kdf.c index 27f57896..3d707bd0 100644 --- a/cipher/kdf.c +++ b/cipher/kdf.c @@ -1,5 +1,5 @@ /* kdf.c - Key Derivation Functions - * Copyright (C) 1998, 2011 Free Software Foundation, Inc. + * Copyright (C) 1998, 2008, 2011 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. @@ -305,3 +305,198 @@ _gcry_kdf_derive (const void *passphrase, size_t passphraselen, leave: return ec; } + + +/* Check one KDF call with ALGO and HASH_ALGO using the regular KDF + * API. (passphrase,passphraselen) is the password to be derived, + * (salt,saltlen) the salt for the key derivation, + * iterations is the number of the kdf iterations, + * and (expect,expectlen) the expected result. Returns NULL on + * success or a string describing the failure. */ + +static const char * +check_one (int algo, int hash_algo, + const void *passphrase, size_t passphraselen, + const void *salt, size_t saltlen, + unsigned long iterations, + const void *expect, size_t expectlen) +{ + unsigned char key[512]; /* hardcoded to avoid allocation */ + size_t keysize = expectlen; + + if (keysize > sizeof(key)) + return "invalid tests data"; + + if (_gcry_kdf_derive (passphrase, passphraselen, algo, + hash_algo, salt, saltlen, iterations, + keysize, key)) + return "gcry_kdf_derive failed"; + + if (memcmp (key, expect, expectlen)) + return "does not match"; + + return NULL; +} + + +static gpg_err_code_t +selftest_pbkdf2 (int extended, selftest_report_func_t report) +{ + static struct { + const char *desc; + const char *p; /* Passphrase. */ + size_t plen; /* Length of P. */ + const char *salt; + size_t saltlen; + int hashalgo; + unsigned long c; /* Iterations. */ + int dklen; /* Requested key length. */ + const char *dk; /* Derived key. */ + int disabled; + } tv[] = { +#if USE_SHA1 +#define NUM_TEST_VECTORS 9 + /* SHA1 test vectors are from RFC-6070. */ + { + "Basic PBKDF2 SHA1 #1", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 1, + 20, + "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9" + "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6" + }, + { + "Basic PBKDF2 SHA1 #2", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 2, + 20, + "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e" + "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57" + }, + { + "Basic PBKDF2 SHA1 #3", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 4096, + 20, + "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad" + "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1" + }, + { + "Basic PBKDF2 SHA1 #4", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 16777216, + 20, + "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94" + "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", + 1 /* This test takes too long. */ + }, + { + "Basic PBKDF2 SHA1 #5", + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_SHA1, + 4096, + 25, + "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8" + "\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96" + "\x4c\xf2\xf0\x70\x38" + }, + { + "Basic PBKDF2 SHA1 #6", + "pass\0word", 9, + "sa\0lt", 5, + GCRY_MD_SHA1, + 4096, + 16, + "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37" + "\xd7\xf0\x34\x25\xe0\xc3" + }, + { /* empty password test, not in RFC-6070 */ + "Basic PBKDF2 SHA1 #7", + "", 0, + "salt", 4, + GCRY_MD_SHA1, + 2, + 20, + "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2" + "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97" + }, +#else +#define NUM_TEST_VECTORS 2 +#endif + { + "Basic PBKDF2 SHA256", + "password", 8, + "salt", 4, + GCRY_MD_SHA256, + 2, + 32, + "\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0" + "\x2a\x30\x3f\x8e\xf3\xc2\x51\xdf\xd6\xe2\xd8\x5a\x95\x47\x4c\x43" + }, + { + "Extended PBKDF2 SHA256", + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_SHA256, + 4096, + 40, + "\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf" + "\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c\x4e\x2a\x1f\xb8\xdd\x53\xe1" + "\xc6\x35\x51\x8c\x7d\xac\x47\xe9" + } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + if (tv[tvidx].disabled) + continue; + errtxt = check_one (GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, + tv[tvidx].p, tv[tvidx].plen, + tv[tvidx].salt, tv[tvidx].saltlen, + tv[tvidx].c, + tv[tvidx].dk, tv[tvidx].dklen); + if (errtxt) + goto failed; + if (tvidx >= NUM_TEST_VECTORS - 1 && !extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("kdf", GCRY_KDF_PBKDF2, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run the selftests for KDF with KDF algorithm ALGO with optional + reporting function REPORT. */ +gpg_error_t +_gcry_kdf_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_err_code_t ec = 0; + + if (algo == GCRY_KDF_PBKDF2) + ec = selftest_pbkdf2 (extended, report); + else + { + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; + if (report) + report ("kdf", algo, "module", "algorithm not available"); + } + return gpg_error (ec); +} |