qemu/crypto/hmac-gcrypt.c
<<
>>
Prefs
   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 "hmacpriv.h"
  19#include <gcrypt.h>
  20
  21static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
  22    [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5,
  23    [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1,
  24    [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224,
  25    [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256,
  26    [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
  27    [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
  28    [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
  29};
  30
  31typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
  32struct QCryptoHmacGcrypt {
  33    gcry_mac_hd_t handle;
  34};
  35
  36bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
  37{
  38    if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
  39        qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) {
  40        return true;
  41    }
  42
  43    return false;
  44}
  45
  46void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
  47                           const uint8_t *key, size_t nkey,
  48                           Error **errp)
  49{
  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_str(alg));
  56        return NULL;
  57    }
  58
  59    ctx = g_new0(QCryptoHmacGcrypt, 1);
  60
  61    err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg],
  62                        GCRY_MAC_FLAG_SECURE, NULL);
  63    if (err != 0) {
  64        error_setg(errp, "Cannot initialize hmac: %s",
  65                   gcry_strerror(err));
  66        goto error;
  67    }
  68
  69    err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey);
  70    if (err != 0) {
  71        error_setg(errp, "Cannot set key: %s",
  72                   gcry_strerror(err));
  73        gcry_mac_close(ctx->handle);
  74        goto error;
  75    }
  76
  77    return ctx;
  78
  79error:
  80    g_free(ctx);
  81    return NULL;
  82}
  83
  84static void
  85qcrypto_gcrypt_hmac_ctx_free(QCryptoHmac *hmac)
  86{
  87    QCryptoHmacGcrypt *ctx;
  88
  89    ctx = hmac->opaque;
  90    gcry_mac_close(ctx->handle);
  91
  92    g_free(ctx);
  93}
  94
  95static int
  96qcrypto_gcrypt_hmac_bytesv(QCryptoHmac *hmac,
  97                           const struct iovec *iov,
  98                           size_t niov,
  99                           uint8_t **result,
 100                           size_t *resultlen,
 101                           Error **errp)
 102{
 103    QCryptoHmacGcrypt *ctx;
 104    gcry_error_t err;
 105    uint32_t ret;
 106    int i;
 107
 108    ctx = hmac->opaque;
 109
 110    for (i = 0; i < niov; i++) {
 111        gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len);
 112    }
 113
 114    ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]);
 115    if (ret <= 0) {
 116        error_setg(errp, "Unable to get hmac length: %s",
 117                   gcry_strerror(ret));
 118        return -1;
 119    }
 120
 121    if (*resultlen == 0) {
 122        *resultlen = ret;
 123        *result = g_new0(uint8_t, *resultlen);
 124    } else if (*resultlen != ret) {
 125        error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
 126                   *resultlen, ret);
 127        return -1;
 128    }
 129
 130    err = gcry_mac_read(ctx->handle, *result, resultlen);
 131    if (err != 0) {
 132        error_setg(errp, "Cannot get result: %s",
 133                   gcry_strerror(err));
 134        return -1;
 135    }
 136
 137    err = gcry_mac_reset(ctx->handle);
 138    if (err != 0) {
 139        error_setg(errp, "Cannot reset hmac context: %s",
 140                   gcry_strerror(err));
 141        return -1;
 142    }
 143
 144    return 0;
 145}
 146
 147QCryptoHmacDriver qcrypto_hmac_lib_driver = {
 148    .hmac_bytesv = qcrypto_gcrypt_hmac_bytesv,
 149    .hmac_free = qcrypto_gcrypt_hmac_ctx_free,
 150};
 151