1 /* 2 * QEMU Crypto hmac algorithms (based on glib) 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 19 /* Support for HMAC Algos has been added in GLib 2.30 */ 20 #if GLIB_CHECK_VERSION(2, 30, 0) 21 22 static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { 23 [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5, 24 [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1, 25 [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256, 26 /* Support for HMAC SHA-512 in GLib 2.42 */ 27 #if GLIB_CHECK_VERSION(2, 42, 0) 28 [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512, 29 #else 30 [QCRYPTO_HASH_ALG_SHA512] = -1, 31 #endif 32 [QCRYPTO_HASH_ALG_SHA224] = -1, 33 [QCRYPTO_HASH_ALG_SHA384] = -1, 34 [QCRYPTO_HASH_ALG_RIPEMD160] = -1, 35 }; 36 37 typedef struct QCryptoHmacGlib QCryptoHmacGlib; 38 struct QCryptoHmacGlib { 39 GHmac *ghmac; 40 }; 41 42 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) 43 { 44 if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && 45 qcrypto_hmac_alg_map[alg] != -1) { 46 return true; 47 } 48 49 return false; 50 } 51 52 QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, 53 const uint8_t *key, size_t nkey, 54 Error **errp) 55 { 56 QCryptoHmac *hmac; 57 QCryptoHmacGlib *ctx; 58 59 if (!qcrypto_hmac_supports(alg)) { 60 error_setg(errp, "Unsupported hmac algorithm %s", 61 QCryptoHashAlgorithm_lookup[alg]); 62 return NULL; 63 } 64 65 hmac = g_new0(QCryptoHmac, 1); 66 hmac->alg = alg; 67 68 ctx = g_new0(QCryptoHmacGlib, 1); 69 70 ctx->ghmac = g_hmac_new(qcrypto_hmac_alg_map[alg], 71 (const uint8_t *)key, nkey); 72 if (!ctx->ghmac) { 73 error_setg(errp, "Cannot initialize hmac and set key"); 74 goto error; 75 } 76 77 hmac->opaque = ctx; 78 return hmac; 79 80 error: 81 g_free(ctx); 82 g_free(hmac); 83 return NULL; 84 } 85 86 void qcrypto_hmac_free(QCryptoHmac *hmac) 87 { 88 QCryptoHmacGlib *ctx; 89 90 if (!hmac) { 91 return; 92 } 93 94 ctx = hmac->opaque; 95 g_hmac_unref(ctx->ghmac); 96 97 g_free(ctx); 98 g_free(hmac); 99 } 100 101 int qcrypto_hmac_bytesv(QCryptoHmac *hmac, 102 const struct iovec *iov, 103 size_t niov, 104 uint8_t **result, 105 size_t *resultlen, 106 Error **errp) 107 { 108 QCryptoHmacGlib *ctx; 109 int i, ret; 110 111 ctx = hmac->opaque; 112 113 for (i = 0; i < niov; i++) { 114 g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len); 115 } 116 117 ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]); 118 if (ret < 0) { 119 error_setg(errp, "Unable to get hmac length"); 120 return -1; 121 } 122 123 if (*resultlen == 0) { 124 *resultlen = ret; 125 *result = g_new0(uint8_t, *resultlen); 126 } else if (*resultlen != ret) { 127 error_setg(errp, "Result buffer size %zu is smaller than hmac %d", 128 *resultlen, ret); 129 return -1; 130 } 131 132 g_hmac_get_digest(ctx->ghmac, *result, resultlen); 133 134 return 0; 135 } 136 137 #else 138 139 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) 140 { 141 return false; 142 } 143 144 QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, 145 const uint8_t *key, size_t nkey, 146 Error **errp) 147 { 148 return NULL; 149 } 150 151 void qcrypto_hmac_free(QCryptoHmac *hmac) 152 { 153 return; 154 } 155 156 int qcrypto_hmac_bytesv(QCryptoHmac *hmac, 157 const struct iovec *iov, 158 size_t niov, 159 uint8_t **result, 160 size_t *resultlen, 161 Error **errp) 162 { 163 return -1; 164 } 165 166 #endif 167