Merge qcrypto 2016/12/21 v2
-----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJYW675AAoJEL6G67QVEE/fKYUQAIAcO11lKCuAZiLS2ylAL5KB WzgqTG8WWNdbyZoBcN3ObN0m+H6d+o91xJ7PyeftgBV80VVXkhs2j+sUUreAKDUD 6XqxeD+LYScDAGRx/OyYKKi1XXgWfmRP8WBJGWJ2Yk8JghiRtDNaqTgqoAuKwEMB RtknkM1Y0zokA0873B0belUB6nzAfTqJmTbX9/aKtaWNS++gmfLO+K7tbA25UsyR pHaB7Ifx92KkskrcPVP/mBBiMF6BeJNu2xfMF9XiDGEQv2mhyYecDjYNgiFcMqU3 ghKPPmerkVX9qUC47V0XHnQ32xnA5UssC0i5PaZpkL6k2w91G2I8l8A+0ue3EWpy FtbfwyB0JUveT1rLIUdtfWxmls0eHuYOue8EgAmX9Eo4miVVrdpvu7qVCHoVqDFD ta/i9CHaiNybS/A4N0k3lEzxmvTlZeNDAR75WGjs6VW9qBK+OyFfuRqUVHeA2D9x LLIovnOAP8Z43CIxSrsptxSJbvpzLRNFoJzX1fUrTXXxJQvkTOUhHoK2uDTv/9yr 5fp+haj/wpT+vN0sAYvGBdrbiUpousEQuFNK7ElFeVVVH4L8s95xdWq9hO1YBCHm HjxIU7tDKJXh6OzR1RpkAp9zHFOwCPD/90LjWkXWGGHj+Ow80YPsncGnv7lkLKGg dqiwx0BGddfZNzWSQU42 =Fe2e -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange/tags/pull-qcrypto-2016-12-21-2' into staging Merge qcrypto 2016/12/21 v2 # gpg: Signature made Thu 22 Dec 2016 10:46:17 GMT # gpg: using RSA key 0xBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange/tags/pull-qcrypto-2016-12-21-2: crypto: add HMAC algorithms testcases crypto: support HMAC algorithms based on nettle crypto: support HMAC algorithms based on glib crypto: support HMAC algorithms based on libgcrypt crypto: add HMAC algorithms framework configure: add CONFIG_GCRYPT_HMAC item crypto: add 3des-ede support when using libgcrypt/nettle cipher: fix leak on initialization error Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c76904ef2f
17
configure
vendored
17
configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
152
crypto/hmac-gcrypt.c
Normal file
152
crypto/hmac-gcrypt.c
Normal file
@ -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;
|
||||
}
|
166
crypto/hmac-glib.c
Normal file
166
crypto/hmac-glib.c
Normal file
@ -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
|
175
crypto/hmac-nettle.c
Normal file
175
crypto/hmac-nettle.c
Normal file
@ -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;
|
||||
}
|
72
crypto/hmac.c
Normal file
72
crypto/hmac.c
Normal file
@ -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);
|
||||
}
|
166
crypto/hmac.h
Normal file
166
crypto/hmac.h
Normal file
@ -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
|
@ -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']}
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
|
266
tests/test-crypto-hmac.c
Normal file
266
tests/test-crypto-hmac.c
Normal file
@ -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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user