diff options
author | Daniel P. Berrange <berrange@redhat.com> | 2016-09-07 13:12:28 +0100 |
---|---|---|
committer | Daniel P. Berrange <berrange@redhat.com> | 2016-09-19 16:30:45 +0100 |
commit | 533008f4f382490f817a0c313f2d32f6173c08c7 (patch) | |
tree | 79e6b5a6b136d9901480f93275bf618248cca654 | |
parent | 2ab66cd577d6d0ec3c44b14cc823e76ea5a4397c (diff) |
crypto: support more hash algorithms for pbkdf
Currently pbkdf is only supported with SHA1 and SHA256. Expand
this to support all algorithms known to QEMU.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
-rw-r--r-- | crypto/pbkdf-gcrypt.c | 12 | ||||
-rw-r--r-- | crypto/pbkdf-nettle.c | 63 | ||||
-rw-r--r-- | tests/test-crypto-pbkdf.c | 53 |
3 files changed, 117 insertions, 11 deletions
diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c index 44cf31aff4..40289858bf 100644 --- a/crypto/pbkdf-gcrypt.c +++ b/crypto/pbkdf-gcrypt.c @@ -28,7 +28,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) switch (hash) { case QCRYPTO_HASH_ALG_MD5: case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: return true; default: return false; @@ -45,7 +49,11 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, static const int hash_map[QCRYPTO_HASH_ALG__MAX] = { [QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5, [QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224, [QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160, }; int ret; @@ -58,7 +66,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, if (hash >= G_N_ELEMENTS(hash_map) || hash_map[hash] == GCRY_MD_NONE) { - error_setg(errp, "Unexpected hash algorithm %d", hash); + error_setg_errno(errp, ENOSYS, + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_lookup[hash]); return -1; } diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c index db81517adc..6fb2671656 100644 --- a/crypto/pbkdf-nettle.c +++ b/crypto/pbkdf-nettle.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include <nettle/pbkdf2.h> +#include <nettle/hmac.h> #include "qapi/error.h" #include "crypto/pbkdf.h" @@ -28,7 +29,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) { switch (hash) { case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: return true; default: return false; @@ -42,30 +47,70 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, uint8_t *out, size_t nout, Error **errp) { + union { + struct hmac_md5_ctx md5; + struct hmac_sha1_ctx sha1; + struct hmac_sha224_ctx sha224; + struct hmac_sha256_ctx sha256; + struct hmac_sha384_ctx sha384; + struct hmac_sha512_ctx sha512; + struct hmac_ripemd160_ctx ripemd160; + } ctx; + if (iterations > UINT_MAX) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu must be less than %u", (long long unsigned)iterations, UINT_MAX); return -1; } + switch (hash) { + case QCRYPTO_HASH_ALG_MD5: + hmac_md5_set_key(&ctx.md5, nkey, key); + PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest, + MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + case QCRYPTO_HASH_ALG_SHA1: - pbkdf2_hmac_sha1(nkey, key, - iterations, - nsalt, salt, - nout, out); + hmac_sha1_set_key(&ctx.sha1, nkey, key); + PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest, + SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA224: + hmac_sha224_set_key(&ctx.sha224, nkey, key); + PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest, + SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out); break; case QCRYPTO_HASH_ALG_SHA256: - pbkdf2_hmac_sha256(nkey, key, - iterations, - nsalt, salt, - nout, out); + hmac_sha256_set_key(&ctx.sha256, nkey, key); + PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest, + SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA384: + hmac_sha384_set_key(&ctx.sha384, nkey, key); + PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest, + SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA512: + hmac_sha512_set_key(&ctx.sha512, nkey, key); + PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest, + SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_RIPEMD160: + hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key); + PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest, + RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out); break; default: error_setg_errno(errp, ENOSYS, - "PBKDF does not support hash algorithm %d", hash); + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_lookup[hash]); return -1; } return 0; diff --git a/tests/test-crypto-pbkdf.c b/tests/test-crypto-pbkdf.c index a651dc50a3..d937aff6b2 100644 --- a/tests/test-crypto-pbkdf.c +++ b/tests/test-crypto-pbkdf.c @@ -261,7 +261,6 @@ static QCryptoPbkdfTestData test_data[] = { "\xcc\x4a\x5e\x6d\xca\x04\xec\x58", .nout = 32 }, -#if 0 { .path = "/crypto/pbkdf/nonrfc/sha512/iter1200", .hash = QCRYPTO_HASH_ALG_SHA512, @@ -280,6 +279,58 @@ static QCryptoPbkdfTestData test_data[] = { .nout = 32 }, { + .path = "/crypto/pbkdf/nonrfc/sha224/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA224, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x13\x3b\x88\x0c\x0e\x52\xa2\x41" + "\x49\x33\x35\xa6\xc3\x83\xae\x23" + "\xf6\x77\x43\x9e\x5b\x30\x92\x3e" + "\x4a\x3a\xaa\x24\x69\x3c\xed\x20", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/nonrfc/sha384/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA384, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\xfe\xe3\xe1\x84\xc9\x25\x3e\x10" + "\x47\xc8\x7d\x53\xc6\xa5\xe3\x77" + "\x29\x41\x76\xbd\x4b\xe3\x9b\xac" + "\x05\x6c\x11\xdd\x17\xc5\x93\x80", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200", + .hash = QCRYPTO_HASH_ALG_RIPEMD160, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\xd6\xcb\xd8\xa7\xdb\x0c\xa2\x2a" + "\x23\x5e\x47\xaf\xdb\xda\xa8\xef" + "\xe4\x01\x0d\x6f\xb5\x33\xc8\xbd" + "\xce\xbf\x91\x14\x8b\x5c\x48\x41", + .nout = 32 + }, +#if 0 + { .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200", .hash = QCRYPTO_HASH_ALG_WHIRLPOOL, .iterations = 1200, |