|  | /* | 
|  | * 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 "crypto/hmac.h" | 
|  | #include "hmacpriv.h" | 
|  |  | 
|  | static const char hex[] = "0123456789abcdef"; | 
|  |  | 
|  | int qcrypto_hmac_bytesv(QCryptoHmac *hmac, | 
|  | const struct iovec *iov, | 
|  | size_t niov, | 
|  | uint8_t **result, | 
|  | size_t *resultlen, | 
|  | Error **errp) | 
|  | { | 
|  | QCryptoHmacDriver *drv = hmac->driver; | 
|  |  | 
|  | return drv->hmac_bytesv(hmac, iov, niov, result, resultlen, errp); | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgo alg, | 
|  | const uint8_t *key, size_t nkey, | 
|  | Error **errp) | 
|  | { | 
|  | QCryptoHmac *hmac; | 
|  | void *ctx = NULL; | 
|  | QCryptoHmacDriver *drv = NULL; | 
|  |  | 
|  | #ifdef CONFIG_AF_ALG | 
|  | ctx = qcrypto_afalg_hmac_ctx_new(alg, key, nkey, NULL); | 
|  | if (ctx) { | 
|  | drv = &qcrypto_hmac_afalg_driver; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (!ctx) { | 
|  | ctx = qcrypto_hmac_ctx_new(alg, key, nkey, errp); | 
|  | if (!ctx) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | drv = &qcrypto_hmac_lib_driver; | 
|  | } | 
|  |  | 
|  | hmac = g_new0(QCryptoHmac, 1); | 
|  | hmac->alg = alg; | 
|  | hmac->opaque = ctx; | 
|  | hmac->driver = (void *)drv; | 
|  |  | 
|  | return hmac; | 
|  | } | 
|  |  | 
|  | void qcrypto_hmac_free(QCryptoHmac *hmac) | 
|  | { | 
|  | QCryptoHmacDriver *drv; | 
|  |  | 
|  | if (hmac) { | 
|  | drv = hmac->driver; | 
|  | drv->hmac_free(hmac); | 
|  | g_free(hmac); | 
|  | } | 
|  | } |