diff options
-rwxr-xr-x | configure | 17 | ||||
-rw-r--r-- | crypto/Makefile.objs | 4 | ||||
-rw-r--r-- | crypto/cipher-gcrypt.c | 6 | ||||
-rw-r--r-- | crypto/cipher-nettle.c | 42 | ||||
-rw-r--r-- | crypto/cipher.c | 7 | ||||
-rw-r--r-- | crypto/hmac-gcrypt.c | 152 | ||||
-rw-r--r-- | crypto/hmac-glib.c | 166 | ||||
-rw-r--r-- | crypto/hmac-nettle.c | 175 | ||||
-rw-r--r-- | crypto/hmac.c | 72 | ||||
-rw-r--r-- | crypto/hmac.h | 166 | ||||
-rw-r--r-- | qapi/crypto.json | 3 | ||||
-rw-r--r-- | tests/Makefile.include | 2 | ||||
-rw-r--r-- | tests/test-crypto-cipher.c | 119 | ||||
-rw-r--r-- | tests/test-crypto-hmac.c | 266 |
14 files changed, 1191 insertions, 6 deletions
@@ -313,6 +313,7 @@ gnutls_rnd="" nettle="" nettle_kdf="no" gcrypt="" +gcrypt_hmac="no" gcrypt_kdf="no" vte="" virglrenderer="" @@ -2417,6 +2418,19 @@ EOF if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then gcrypt_kdf=yes fi + + cat > $TMPC << EOF +#include <gcrypt.h> +int main(void) { + gcry_mac_hd_t handle; + gcry_mac_open(&handle, GCRY_MAC_HMAC_MD5, + GCRY_MAC_FLAG_SECURE, NULL); + return 0; +} +EOF + if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then + gcrypt_hmac=yes + fi else if test "$gcrypt" = "yes"; then feature_not_found "gcrypt" "Install gcrypt devel" @@ -5387,6 +5401,9 @@ if test "$gnutls_rnd" = "yes" ; then fi if test "$gcrypt" = "yes" ; then echo "CONFIG_GCRYPT=y" >> $config_host_mak + if test "$gcrypt_hmac" = "yes" ; then + echo "CONFIG_GCRYPT_HMAC=y" >> $config_host_mak + fi if test "$gcrypt_kdf" = "yes" ; then echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak fi diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index a36d2d9..1f749f2 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -3,6 +3,10 @@ crypto-obj-y += hash.o crypto-obj-$(CONFIG_NETTLE) += hash-nettle.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += hash-gcrypt.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT),n,y)) += hash-glib.o +crypto-obj-y += hmac.o +crypto-obj-$(CONFIG_NETTLE) += hmac-nettle.o +crypto-obj-$(CONFIG_GCRYPT_HMAC) += hmac-gcrypt.o +crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT_HMAC),n,y)) += hmac-glib.o crypto-obj-y += aes.o crypto-obj-y += desrfb.o crypto-obj-y += cipher.o diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c index c550db9..6487eca 100644 --- a/crypto/cipher-gcrypt.c +++ b/crypto/cipher-gcrypt.c @@ -29,6 +29,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, { switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -99,6 +100,10 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg = GCRY_CIPHER_DES; break; + case QCRYPTO_CIPHER_ALG_3DES: + gcryalg = GCRY_CIPHER_3DES; + break; + case QCRYPTO_CIPHER_ALG_AES_128: gcryalg = GCRY_CIPHER_AES128; break; @@ -200,6 +205,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_ALG_TWOFISH_256: ctx->blocksize = 16; break; + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_CAST5_128: ctx->blocksize = 8; break; diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c index cd094cd..dfc9030 100644 --- a/crypto/cipher-nettle.c +++ b/crypto/cipher-nettle.c @@ -78,6 +78,18 @@ static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, des_decrypt(ctx, length, dst, src); } +static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, uint8_t *dst, const uint8_t *src) { @@ -140,6 +152,18 @@ static void des_decrypt_wrapper(const void *ctx, size_t length, des_decrypt(ctx, length, dst, src); } +static void des3_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + static void cast128_encrypt_wrapper(const void *ctx, size_t length, uint8_t *dst, const uint8_t *src) { @@ -197,6 +221,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, { switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -254,6 +279,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, cipher->mode = mode; ctx = g_new0(QCryptoCipherNettle, 1); + cipher->opaque = ctx; switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: @@ -270,6 +296,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize = DES_BLOCK_SIZE; break; + case QCRYPTO_CIPHER_ALG_3DES: + ctx->ctx = g_new0(struct des3_ctx, 1); + des3_set_key(ctx->ctx, key); + + ctx->alg_encrypt_native = des3_encrypt_native; + ctx->alg_decrypt_native = des3_decrypt_native; + ctx->alg_encrypt_wrapper = des3_encrypt_wrapper; + ctx->alg_decrypt_wrapper = des3_decrypt_wrapper; + + ctx->blocksize = DES3_BLOCK_SIZE; + break; + case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -384,13 +422,11 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, } ctx->iv = g_new0(uint8_t, ctx->blocksize); - cipher->opaque = ctx; return cipher; error: - g_free(cipher); - g_free(ctx); + qcrypto_cipher_free(cipher); return NULL; } diff --git a/crypto/cipher.c b/crypto/cipher.c index a9bca41..9ecaff7 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -28,6 +28,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 24, [QCRYPTO_CIPHER_ALG_AES_256] = 32, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_3DES] = 24, [QCRYPTO_CIPHER_ALG_CAST5_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24, @@ -42,6 +43,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 16, [QCRYPTO_CIPHER_ALG_AES_256] = 16, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_3DES] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 8, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16, @@ -107,8 +109,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, } if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { - error_setg(errp, "XTS mode not compatible with DES-RFB"); + if (alg == QCRYPTO_CIPHER_ALG_DES_RFB + || alg == QCRYPTO_CIPHER_ALG_3DES) { + error_setg(errp, "XTS mode not compatible with DES-RFB/3DES"); return false; } if (nkey % 2) { diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c new file mode 100644 index 0000000..21189e6 --- /dev/null +++ b/crypto/hmac-gcrypt.c @@ -0,0 +1,152 @@ +/* + * QEMU Crypto hmac algorithms (based on libgcrypt) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/hmac.h" +#include <gcrypt.h> + +static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5, + [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224, + [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160, +}; + +typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; +struct QCryptoHmacGcrypt { + gcry_mac_hd_t handle; +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacGcrypt *ctx; + gcry_error_t err; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacGcrypt, 1); + + err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg], + GCRY_MAC_FLAG_SECURE, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize hmac: %s", + gcry_strerror(err)); + goto error; + } + + err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey); + if (err != 0) { + error_setg(errp, "Cannot set key: %s", + gcry_strerror(err)); + goto error; + } + + hmac->opaque = ctx; + return hmac; + +error: + g_free(ctx); + g_free(hmac); + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacGcrypt *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + gcry_mac_close(ctx->handle); + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacGcrypt *ctx; + gcry_error_t err; + uint32_t ret; + int i; + + ctx = hmac->opaque; + + for (i = 0; i < niov; i++) { + gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len); + } + + ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]); + if (ret <= 0) { + error_setg(errp, "Unable to get hmac length: %s", + gcry_strerror(ret)); + return -1; + } + + if (*resultlen == 0) { + *resultlen = ret; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != ret) { + error_setg(errp, "Result buffer size %zu is smaller than hmac %d", + *resultlen, ret); + return -1; + } + + err = gcry_mac_read(ctx->handle, *result, resultlen); + if (err != 0) { + error_setg(errp, "Cannot get result: %s", + gcry_strerror(err)); + return -1; + } + + err = gcry_mac_reset(ctx->handle); + if (err != 0) { + error_setg(errp, "Cannot reset hmac context: %s", + gcry_strerror(err)); + return -1; + } + + return 0; +} diff --git a/crypto/hmac-glib.c b/crypto/hmac-glib.c new file mode 100644 index 0000000..08a1fdd --- /dev/null +++ b/crypto/hmac-glib.c @@ -0,0 +1,166 @@ +/* + * QEMU Crypto hmac algorithms (based on glib) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/hmac.h" + +/* Support for HMAC Algos has been added in GLib 2.30 */ +#if GLIB_CHECK_VERSION(2, 30, 0) + +static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5, + [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1, + [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256, +/* Support for HMAC SHA-512 in GLib 2.42 */ +#if GLIB_CHECK_VERSION(2, 42, 0) + [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512, +#else + [QCRYPTO_HASH_ALG_SHA512] = -1, +#endif + [QCRYPTO_HASH_ALG_SHA224] = -1, + [QCRYPTO_HASH_ALG_SHA384] = -1, + [QCRYPTO_HASH_ALG_RIPEMD160] = -1, +}; + +typedef struct QCryptoHmacGlib QCryptoHmacGlib; +struct QCryptoHmacGlib { + GHmac *ghmac; +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg] != -1) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacGlib *ctx; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacGlib, 1); + + ctx->ghmac = g_hmac_new(qcrypto_hmac_alg_map[alg], + (const uint8_t *)key, nkey); + if (!ctx->ghmac) { + error_setg(errp, "Cannot initialize hmac and set key"); + goto error; + } + + hmac->opaque = ctx; + return hmac; + +error: + g_free(ctx); + g_free(hmac); + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacGlib *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + g_hmac_unref(ctx->ghmac); + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacGlib *ctx; + int i, ret; + + ctx = hmac->opaque; + + for (i = 0; i < niov; i++) { + g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len); + } + + ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]); + if (ret < 0) { + error_setg(errp, "Unable to get hmac length"); + return -1; + } + + if (*resultlen == 0) { + *resultlen = ret; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != ret) { + error_setg(errp, "Result buffer size %zu is smaller than hmac %d", + *resultlen, ret); + return -1; + } + + g_hmac_get_digest(ctx->ghmac, *result, resultlen); + + return 0; +} + +#else + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + return; +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + return -1; +} + +#endif diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c new file mode 100644 index 0000000..4a9e6b2 --- /dev/null +++ b/crypto/hmac-nettle.c @@ -0,0 +1,175 @@ +/* + * QEMU Crypto hmac algorithms (based on nettle) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/hmac.h" +#include <nettle/hmac.h> + +typedef void (*qcrypto_nettle_hmac_setkey)(void *ctx, + size_t key_length, const uint8_t *key); + +typedef void (*qcrypto_nettle_hmac_update)(void *ctx, + size_t length, const uint8_t *data); + +typedef void (*qcrypto_nettle_hmac_digest)(void *ctx, + size_t length, uint8_t *digest); + +typedef struct QCryptoHmacNettle QCryptoHmacNettle; +struct QCryptoHmacNettle { + union qcrypto_nettle_hmac_ctx { + struct hmac_md5_ctx md5_ctx; + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */ + struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */ + struct hmac_ripemd160_ctx ripemd160_ctx; + } u; +}; + +struct qcrypto_nettle_hmac_alg { + qcrypto_nettle_hmac_setkey setkey; + qcrypto_nettle_hmac_update update; + qcrypto_nettle_hmac_digest digest; + size_t len; +} qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_md5_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_md5_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_md5_digest, + .len = MD5_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_SHA1] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha1_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sha1_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sha1_digest, + .len = SHA1_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_SHA224] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha224_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sha224_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sha224_digest, + .len = SHA224_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_SHA256] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha256_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sha256_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sha256_digest, + .len = SHA256_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_SHA384] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha384_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sha384_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sha384_digest, + .len = SHA384_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_SHA512] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha512_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_sha512_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_sha512_digest, + .len = SHA512_DIGEST_SIZE, + }, + [QCRYPTO_HASH_ALG_RIPEMD160] = { + .setkey = (qcrypto_nettle_hmac_setkey)hmac_ripemd160_set_key, + .update = (qcrypto_nettle_hmac_update)hmac_ripemd160_update, + .digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest, + .len = RIPEMD160_DIGEST_SIZE, + }, +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg].setkey != NULL) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacNettle *ctx; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacNettle, 1); + + qcrypto_hmac_alg_map[alg].setkey(&ctx->u, nkey, key); + + hmac->opaque = ctx; + + return hmac; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacNettle *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacNettle *ctx; + int i; + + ctx = (QCryptoHmacNettle *)hmac->opaque; + + for (i = 0; i < niov; ++i) { + size_t len = iov[i].iov_len; + uint8_t *base = iov[i].iov_base; + while (len) { + size_t shortlen = MIN(len, UINT_MAX); + qcrypto_hmac_alg_map[hmac->alg].update(&ctx->u, len, base); + len -= shortlen; + base += len; + } + } + + if (*resultlen == 0) { + *resultlen = qcrypto_hmac_alg_map[hmac->alg].len; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != qcrypto_hmac_alg_map[hmac->alg].len) { + error_setg(errp, + "Result buffer size %zu is smaller than hash %zu", + *resultlen, qcrypto_hmac_alg_map[hmac->alg].len); + return -1; + } + + qcrypto_hmac_alg_map[hmac->alg].digest(&ctx->u, *resultlen, *result); + + return 0; +} diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 0000000..5750405 --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,72 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/hmac.h" + +static const char hex[] = "0123456789abcdef"; + +int qcrypto_hmac_bytes(QCryptoHmac *hmac, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + struct iovec iov = { + .iov_base = (char *)buf, + .iov_len = len + }; + + return qcrypto_hmac_bytesv(hmac, &iov, 1, result, resultlen, errp); +} + +int qcrypto_hmac_digestv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp) +{ + uint8_t *result = NULL; + size_t resultlen = 0; + size_t i; + + if (qcrypto_hmac_bytesv(hmac, iov, niov, &result, &resultlen, errp) < 0) { + return -1; + } + + *digest = g_new0(char, (resultlen * 2) + 1); + + for (i = 0 ; i < resultlen ; i++) { + (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; + (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; + } + + (*digest)[resultlen * 2] = '\0'; + + g_free(result); + return 0; +} + +int qcrypto_hmac_digest(QCryptoHmac *hmac, + const char *buf, + size_t len, + char **digest, + Error **errp) +{ + struct iovec iov = { + .iov_base = (char *)buf, + .iov_len = len + }; + + return qcrypto_hmac_digestv(hmac, &iov, 1, digest, errp); +} diff --git a/crypto/hmac.h b/crypto/hmac.h new file mode 100644 index 0000000..0d3acd7 --- /dev/null +++ b/crypto/hmac.h @@ -0,0 +1,166 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#ifndef QCRYPTO_HMAC_H +#define QCRYPTO_HMAC_H + +#include "qapi-types.h" + +typedef struct QCryptoHmac QCryptoHmac; +struct QCryptoHmac { + QCryptoHashAlgorithm alg; + void *opaque; +}; + +/** + * qcrypto_hmac_supports: + * @alg: the hmac algorithm + * + * Determine if @alg hmac algorithm is supported by + * the current configured build + * + * Returns: + * true if the algorithm is supported, false otherwise + */ +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg); + +/** + * qcrypto_hmac_new: + * @alg: the hmac algorithm + * @key: the key bytes + * @nkey: the length of @key + * @errp: pointer to a NULL-initialized error object + * + * Creates a new hmac object with the algorithm @alg + * + * The @key parameter provides the bytes representing + * the secret key to use. The @nkey parameter specifies + * the length of @key in bytes + * + * Note: must use qcrypto_hmac_free() to release the + * returned hmac object when no longer required + * + * Returns: + * a new hmac object, or NULL on error + */ +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp); + +/** + * qcrypto_hmac_free: + * @hmac: the hmac object + * + * Release the memory associated with @hmac that was + * previously allocated by qcrypto_hmac_new() + */ +void qcrypto_hmac_free(QCryptoHmac *hmac); + +/** + * qcrypto_hmac_bytesv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory regions + * present in @iov. The @result pointer will be + * filled with raw bytes representing the computed + * hmac, which will have length @resultlen. The + * memory pointer in @result must be released + * with a call to g_free() when no longer required. + * + * Returns: + * 0 on success, -1 on error + */ +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_bytes: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory region + * @buf of length @len. The @result pointer will be + * filled with raw bytes representing the computed + * hmac, which will have length @resultlen. The + * memory pointer in @result must be released + * with a call to g_free() when no longer required. + * + * Returns: + * 0 on success, -1 on error + */ +int qcrypto_hmac_bytes(QCryptoHmac *hmac, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_digestv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory regions + * present in @iov. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, which will be terminated by '\0'. The + * memory pointer in @digest must be released + * with a call to g_free() when no longer required. + * + * Returns: + * 0 on success, -1 on error + */ +int qcrypto_hmac_digestv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp); + +/** + * qcrypto_hmac_digest: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory region + * @buf of length @len. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, which will be terminated by '\0'. The + * memory pointer in @digest must be released + * with a call to g_free() when no longer required. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_hmac_digest(QCryptoHmac *hmac, + const char *buf, + size_t len, + char **digest, + Error **errp); + +#endif diff --git a/qapi/crypto.json b/qapi/crypto.json index 15d296e..f4fd93b 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -63,6 +63,7 @@ # @aes-192: AES with 192 bit / 24 byte keys # @aes-256: AES with 256 bit / 32 byte keys # @des-rfb: RFB specific variant of single DES. Do not use except in VNC. +# @3des: 3DES(EDE) with 192 bit / 24 byte keys (since 2.9) # @cast5-128: Cast5 with 128 bit / 16 byte keys # @serpent-128: Serpent with 128 bit / 16 byte keys # @serpent-192: Serpent with 192 bit / 24 byte keys @@ -75,7 +76,7 @@ { 'enum': 'QCryptoCipherAlgorithm', 'prefix': 'QCRYPTO_CIPHER_ALG', 'data': ['aes-128', 'aes-192', 'aes-256', - 'des-rfb', + 'des-rfb', '3des', 'cast5-128', 'serpent-128', 'serpent-192', 'serpent-256', 'twofish-128', 'twofish-192', 'twofish-256']} diff --git a/tests/Makefile.include b/tests/Makefile.include index e98d3b6..4841d58 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -91,6 +91,7 @@ gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c check-unit-y += tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y = block/write-threshold.c check-unit-y += tests/test-crypto-hash$(EXESUF) +check-unit-y += tests/test-crypto-hmac$(EXESUF) check-unit-y += tests/test-crypto-cipher$(EXESUF) check-unit-y += tests/test-crypto-secret$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) @@ -571,6 +572,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y) tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y) tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y) +tests/test-crypto-hmac$(EXESUF): tests/test-crypto-hmac.o $(test-crypto-obj-y) tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y) tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c index 5d9e535..07fa2fa 100644 --- a/tests/test-crypto-cipher.c +++ b/tests/test-crypto-cipher.c @@ -165,6 +165,125 @@ static QCryptoCipherTestData test_data[] = { "ffd29f1bb5596ad94ea2d8e6196b7f09" "30d8ed0bf2773af36dd82a6280c20926", }, +#if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-cbc", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = + "e9c0ff2e760b6424444d995a12d640c0" + "eac284e81495dbe8", + .iv = + "7d3388930f93b242", + .plaintext = + "6f54206f614d796e5320636565727374" + "54206f6f4d206e612079655372637465" + "20736f54206f614d796e532063656572" + "737454206f6f4d206e61207965537263" + "746520736f54206f614d796e53206365" + "6572737454206f6f4d206e6120796553" + "7263746520736f54206f614d796e5320" + "63656572737454206f6f4d206e610a79", + .ciphertext = + "0e2db6973c5633f4671721c76e8ad549" + "74b34905c51cd0ed12565c5396b6007d" + "9048fcf58d2939cc8ad5351836234ed7" + "76d1da0c9467bb048bf2036ca8cfb6ea" + "226447aa8f7513bf9fc2c3f0c956c57a" + "71632e897b1e12cae25fafd8a4f8c97a" + "d6f92131624445a6d6bc5ad32d5443cc" + "9ddea570e942458a6bfab19113b0d919", + }, + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-ecb", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = + "0123456789abcdef5555555555555555" + "fedcba9876543210", + .plaintext = + "736f6d6564617461", + .ciphertext = + "18d748e563620572", + }, + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-ctr", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_CTR, + .key = + "9cd6f39cb95a67005a67002dceeb2dce" + "ebb45172b451721f", + .iv = + "ffffffffffffffff", + .plaintext = + "05ec77fb42d559208b128669f05bcf56" + "39ad349f66ea7dc448d3ba0db118e34a" + "fe41285c278e11856cf75ec2553ca00b" + "9265e970db4fd6b900b41fe649fd442f" + "533a8d149863ca5dc1a833a70e9178ec" + "77de42d5bc078b12e54cf05b22563980" + "6b9f66c950c4af36ba0d947fe34add41" + "28b31a8e11f843f75e21553c876e9265" + "cc57dba235b900eb72e649d0442fb619" + "8d14ff46ca5d24a8339a6d9178c377de" + "a108bc07ee71e54cd75b22b51c806bf2" + "45c9503baf369960947fc64adda40fb3" + "1aed74f8432a5e218813876ef158cc57" + "3ea2359c67eb72c549d0bb02b619e04b" + "ff46295d248f169a6df45fc3aa3da108" + "937aee71d84cd7be01b51ce74ef2452c" + "503b82159960cb52c6a930a40f9679ed" + "74df432abd048813fa4df15823573e81" + "689c67ce51c5ac37bb02957ce04bd246" + "29b01b8f16f940f45f26aa3d846f937a" + "cd54d8a30abe01e873e74ed1452cb71e" + "8215fc47cb5225a9309b629679c074df" + "a609bd04ef76fa4dd458238a1d8168f3" + "5ace5138ac379e61957cc74bd2a50cb0" + "1be275f9402b5f268910846ff659cd54" + "3fa30a9d64e873da4ed1b803b71ee148" + "fc472e52258c179b62f55cc0ab32a609" + "907bef76d94dd4bf068a1de44ff35a2d" + "5138836a9e61c853c7ae31a50c977ee2" + "75dc402bb2058910fb42f65920543f86" + "699d64cf56daad34b803ea7de148d347", + .ciphertext = + "07c20820721f49ef19cd6f3253052215" + "a2852bdb85d2d8b9dd0d1b45cb6911d4" + "eabeb2455d0caebea0c127ac659f537e" + "afc21bb5b86d360c25c0f86d0b2901da" + "1378dc89121243faf612ef8d87627883" + "e2be41204c6d351bd10c30cfe2de2b03" + "bf4573d4e55995d1b39b276297bdde7f" + "a4d23980aa5023f074883da86a18793b" + "c4966c8d2240926ed6ad2a1fde63c0e7" + "07f72df7b5f3f0cc017c2a9bc210caaa" + "fd2b3fc5f3f6fc9b45db53e45bf3c97b" + "8e52ffc802b8ac9da10039da3d2d0e01" + "097d8d5ebe53b9b08ee7e2966ab278ea" + "de238ba5fa5ce3dabf8e316a55d16ab2" + "b5466fa5f0eeba1f9f98b0664fd03fa9" + "df5f58c4f4ff755c403a097e6e1c97d4" + "cce7e771cf0b150871fa0797cde6ca1d" + "14280ccf99137af1ebfafa9207de1da1" + "d33669fe514d9f2e83374f1f4830ed04" + "4da4ef3aca76f41c418f6337782f86a6" + "ef417ed2af88ab675271c38ef8269372" + "aad60ee70b46b13ab408a9a8a0cf200c" + "52bc8b0556b2bc319b74b92929969a50" + "dc45dc1aeb0c64d4d3057e5955c3f490" + "c2abf89b8adacea1c3f4ad77dd44c8ac" + "a3f1c9d2195cb0caa234c1f76cfdac65" + "32dc48c4f2006b77f17d76acc031632a" + "a53a62c891b10365cb43d106dfc367bc" + "dce0cd35ce4965a0527ba70d07a91bb0" + "407772c2ea0e3a7846b991b6e73d5142" + "fd51b0c62c6313785ceefccfc4700034", + }, +#endif { /* RFC 2144, Appendix B.1 */ .path = "/crypto/cipher/cast5-128", diff --git a/tests/test-crypto-hmac.c b/tests/test-crypto-hmac.c new file mode 100644 index 0000000..ee55382 --- /dev/null +++ b/tests/test-crypto-hmac.c @@ -0,0 +1,266 @@ +/* + * QEMU Crypto hmac algorithms tests + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "crypto/init.h" +#include "crypto/hmac.h" + +#define INPUT_TEXT1 "ABCDEFGHIJKLMNOPQRSTUVWXY" +#define INPUT_TEXT2 "Zabcdefghijklmnopqrstuvwx" +#define INPUT_TEXT3 "yz0123456789" +#define INPUT_TEXT INPUT_TEXT1 \ + INPUT_TEXT2 \ + INPUT_TEXT3 + +#define KEY "monkey monkey monkey monkey" + +typedef struct QCryptoHmacTestData QCryptoHmacTestData; +struct QCryptoHmacTestData { + QCryptoHashAlgorithm alg; + const char *hex_digest; +}; + +static QCryptoHmacTestData test_data[] = { + { + .alg = QCRYPTO_HASH_ALG_MD5, + .hex_digest = + "ede9cb83679ba82d88fbeae865b3f8fc", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA1, + .hex_digest = + "c7b5a631e3aac975c4ededfcd346e469" + "dbc5f2d1", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA224, + .hex_digest = + "5f768179dbb29ca722875d0f461a2e2f" + "597d0210340a84df1a8e9c63", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA256, + .hex_digest = + "3798f363c57afa6edaffe39016ca7bad" + "efd1e670afb0e3987194307dec3197db", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA384, + .hex_digest = + "d218680a6032d33dccd9882d6a6a7164" + "64f26623be257a9b2919b185294f4a49" + "9e54b190bfd6bc5cedd2cd05c7e65e82", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA512, + .hex_digest = + "835a4f5b3750b4c1fccfa88da2f746a4" + "900160c9f18964309bb736c13b59491b" + "8e32d37b724cc5aebb0f554c6338a3b5" + "94c4ba26862b2dadb59b7ede1d08d53e", + }, + { + .alg = QCRYPTO_HASH_ALG_RIPEMD160, + .hex_digest = + "94964ed4c1155b62b668c241d67279e5" + "8a711676", + }, +}; + +static const char hex[] = "0123456789abcdef"; + +static void test_hmac_alloc(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_prealloc(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + resultlen = strlen(exp_output) / 2; + result = g_new0(uint8_t, resultlen); + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + exp_output = data->hex_digest; + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_iov(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + struct iovec iov[3] = { + { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) }, + { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) }, + { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) }, + }; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytesv(hmac, iov, 3, &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_digest(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_digest(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), (char **)&result, + &err); + g_assert(err == NULL); + g_assert(ret == 0); + + g_assert_cmpstr((const char *)result, ==, exp_output); + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + g_test_add_func("/crypto/hmac/iov", test_hmac_iov); + g_test_add_func("/crypto/hmac/alloc", test_hmac_alloc); + g_test_add_func("/crypto/hmac/prealloc", test_hmac_prealloc); + g_test_add_func("/crypto/hmac/digest", test_hmac_digest); + + return g_test_run(); +} |