1 /* 2 * QEMU Crypto hmac algorithms (based on libgcrypt) 3 * 4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. 5 * 6 * Authors: 7 * Longpeng(Mike) <longpeng2@huawei.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or 10 * (at your option) any later version. See the COPYING file in the 11 * top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "qapi/error.h" 17 #include "crypto/hmac.h" 18 #include <gcrypt.h> 19 20 static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { 21 [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5, 22 [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1, 23 [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224, 24 [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256, 25 [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384, 26 [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512, 27 [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160, 28 }; 29 30 typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; 31 struct QCryptoHmacGcrypt { 32 gcry_mac_hd_t handle; 33 }; 34 35 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) 36 { 37 if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && 38 qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) { 39 return true; 40 } 41 42 return false; 43 } 44 45 QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, 46 const uint8_t *key, size_t nkey, 47 Error **errp) 48 { 49 QCryptoHmac *hmac; 50 QCryptoHmacGcrypt *ctx; 51 gcry_error_t err; 52 53 if (!qcrypto_hmac_supports(alg)) { 54 error_setg(errp, "Unsupported hmac algorithm %s", 55 QCryptoHashAlgorithm_lookup[alg]); 56 return NULL; 57 } 58 59 hmac = g_new0(QCryptoHmac, 1); 60 hmac->alg = alg; 61 62 ctx = g_new0(QCryptoHmacGcrypt, 1); 63 64 err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg], 65 GCRY_MAC_FLAG_SECURE, NULL); 66 if (err != 0) { 67 error_setg(errp, "Cannot initialize hmac: %s", 68 gcry_strerror(err)); 69 goto error; 70 } 71 72 err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey); 73 if (err != 0) { 74 error_setg(errp, "Cannot set key: %s", 75 gcry_strerror(err)); 76 goto error; 77 } 78 79 hmac->opaque = ctx; 80 return hmac; 81 82 error: 83 g_free(ctx); 84 g_free(hmac); 85 return NULL; 86 } 87 88 void qcrypto_hmac_free(QCryptoHmac *hmac) 89 { 90 QCryptoHmacGcrypt *ctx; 91 92 if (!hmac) { 93 return; 94 } 95 96 ctx = hmac->opaque; 97 gcry_mac_close(ctx->handle); 98 99 g_free(ctx); 100 g_free(hmac); 101 } 102 103 int qcrypto_hmac_bytesv(QCryptoHmac *hmac, 104 const struct iovec *iov, 105 size_t niov, 106 uint8_t **result, 107 size_t *resultlen, 108 Error **errp) 109 { 110 QCryptoHmacGcrypt *ctx; 111 gcry_error_t err; 112 uint32_t ret; 113 int i; 114 115 ctx = hmac->opaque; 116 117 for (i = 0; i < niov; i++) { 118 gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len); 119 } 120 121 ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]); 122 if (ret <= 0) { 123 error_setg(errp, "Unable to get hmac length: %s", 124 gcry_strerror(ret)); 125 return -1; 126 } 127 128 if (*resultlen == 0) { 129 *resultlen = ret; 130 *result = g_new0(uint8_t, *resultlen); 131 } else if (*resultlen != ret) { 132 error_setg(errp, "Result buffer size %zu is smaller than hmac %d", 133 *resultlen, ret); 134 return -1; 135 } 136 137 err = gcry_mac_read(ctx->handle, *result, resultlen); 138 if (err != 0) { 139 error_setg(errp, "Cannot get result: %s", 140 gcry_strerror(err)); 141 return -1; 142 } 143 144 err = gcry_mac_reset(ctx->handle); 145 if (err != 0) { 146 error_setg(errp, "Cannot reset hmac context: %s", 147 gcry_strerror(err)); 148 return -1; 149 } 150 151 return 0; 152 } 153