| /* | 
 |  * 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); | 
 |     } | 
 | } |