hmac-gcrypt.c 3.79 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * QEMU Crypto hmac algorithms (based on libgcrypt)
 *
 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
 *
 * Authors:
 *    Longpeng(Mike) <longpeng2@huawei.com>
 *
 * 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 "qapi/error.h"
#include "crypto/hmac.h"
18
#include "hmacpriv.h"
19 20
#include <gcrypt.h>

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
    [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5,
    [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1,
    [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224,
    [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256,
    [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
    [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
    [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
};

typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
struct QCryptoHmacGcrypt {
    gcry_mac_hd_t handle;
};

36 37
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
{
38 39 40 41 42
    if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
        qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) {
        return true;
    }

43 44 45
    return false;
}

46 47 48
void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
                           const uint8_t *key, size_t nkey,
                           Error **errp)
49
{
50 51 52 53 54
    QCryptoHmacGcrypt *ctx;
    gcry_error_t err;

    if (!qcrypto_hmac_supports(alg)) {
        error_setg(errp, "Unsupported hmac algorithm %s",
55
                   QCryptoHashAlgorithm_str(alg));
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
        return NULL;
    }

    ctx = g_new0(QCryptoHmacGcrypt, 1);

    err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg],
                        GCRY_MAC_FLAG_SECURE, NULL);
    if (err != 0) {
        error_setg(errp, "Cannot initialize hmac: %s",
                   gcry_strerror(err));
        goto error;
    }

    err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey);
    if (err != 0) {
        error_setg(errp, "Cannot set key: %s",
                   gcry_strerror(err));
73
        gcry_mac_close(ctx->handle);
74 75 76
        goto error;
    }

77
    return ctx;
78 79 80

error:
    g_free(ctx);
81 82 83
    return NULL;
}

84 85
static void
qcrypto_gcrypt_hmac_ctx_free(QCryptoHmac *hmac)
86
{
87 88 89 90 91 92
    QCryptoHmacGcrypt *ctx;

    ctx = hmac->opaque;
    gcry_mac_close(ctx->handle);

    g_free(ctx);
93 94
}

95 96 97 98 99 100 101
static int
qcrypto_gcrypt_hmac_bytesv(QCryptoHmac *hmac,
                           const struct iovec *iov,
                           size_t niov,
                           uint8_t **result,
                           size_t *resultlen,
                           Error **errp)
102
{
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    QCryptoHmacGcrypt *ctx;
    gcry_error_t err;
    uint32_t ret;
    int i;

    ctx = hmac->opaque;

    for (i = 0; i < niov; i++) {
        gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len);
    }

    ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]);
    if (ret <= 0) {
        error_setg(errp, "Unable to get hmac length: %s",
                   gcry_strerror(ret));
        return -1;
    }

    if (*resultlen == 0) {
        *resultlen = ret;
        *result = g_new0(uint8_t, *resultlen);
    } else if (*resultlen != ret) {
        error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
                   *resultlen, ret);
        return -1;
    }

    err = gcry_mac_read(ctx->handle, *result, resultlen);
    if (err != 0) {
        error_setg(errp, "Cannot get result: %s",
                   gcry_strerror(err));
        return -1;
    }

    err = gcry_mac_reset(ctx->handle);
    if (err != 0) {
        error_setg(errp, "Cannot reset hmac context: %s",
                   gcry_strerror(err));
        return -1;
    }

    return 0;
145
}
146

147 148 149 150
QCryptoHmacDriver qcrypto_hmac_lib_driver = {
    .hmac_bytesv = qcrypto_gcrypt_hmac_bytesv,
    .hmac_free = qcrypto_gcrypt_hmac_ctx_free,
};