]> Git Repo - qemu.git/blob - crypto/hmac-gcrypt.c
crypto: hmac: introduce qcrypto_hmac_ctx_new for gcrypt-backend
[qemu.git] / crypto / hmac-gcrypt.c
1 /*
2  * QEMU Crypto hmac algorithms (based on libgcrypt)
3  *
4  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5  *
6  * Authors:
7  *    Longpeng(Mike) <[email protected]>
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 <gcrypt.h>
19
20 static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
21     [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5,
22     [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1,
23     [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224,
24     [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256,
25     [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
26     [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
27     [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
28 };
29
30 typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
31 struct QCryptoHmacGcrypt {
32     gcry_mac_hd_t handle;
33 };
34
35 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
36 {
37     if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
38         qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) {
39         return true;
40     }
41
42     return false;
43 }
44
45 static QCryptoHmacGcrypt *
46 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_lookup[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
79 error:
80     g_free(ctx);
81     return NULL;
82 }
83
84 void qcrypto_hmac_free(QCryptoHmac *hmac)
85 {
86     QCryptoHmacGcrypt *ctx;
87
88     if (!hmac) {
89         return;
90     }
91
92     ctx = hmac->opaque;
93     gcry_mac_close(ctx->handle);
94
95     g_free(ctx);
96     g_free(hmac);
97 }
98
99 int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
100                         const struct iovec *iov,
101                         size_t niov,
102                         uint8_t **result,
103                         size_t *resultlen,
104                         Error **errp)
105 {
106     QCryptoHmacGcrypt *ctx;
107     gcry_error_t err;
108     uint32_t ret;
109     int i;
110
111     ctx = hmac->opaque;
112
113     for (i = 0; i < niov; i++) {
114         gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len);
115     }
116
117     ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]);
118     if (ret <= 0) {
119         error_setg(errp, "Unable to get hmac length: %s",
120                    gcry_strerror(ret));
121         return -1;
122     }
123
124     if (*resultlen == 0) {
125         *resultlen = ret;
126         *result = g_new0(uint8_t, *resultlen);
127     } else if (*resultlen != ret) {
128         error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
129                    *resultlen, ret);
130         return -1;
131     }
132
133     err = gcry_mac_read(ctx->handle, *result, resultlen);
134     if (err != 0) {
135         error_setg(errp, "Cannot get result: %s",
136                    gcry_strerror(err));
137         return -1;
138     }
139
140     err = gcry_mac_reset(ctx->handle);
141     if (err != 0) {
142         error_setg(errp, "Cannot reset hmac context: %s",
143                    gcry_strerror(err));
144         return -1;
145     }
146
147     return 0;
148 }
149
150 QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
151                               const uint8_t *key, size_t nkey,
152                               Error **errp)
153 {
154     QCryptoHmac *hmac;
155     QCryptoHmacGcrypt *ctx;
156
157     ctx = qcrypto_hmac_ctx_new(alg, key, nkey, errp);
158     if (!ctx) {
159         return NULL;
160     }
161
162     hmac = g_new0(QCryptoHmac, 1);
163     hmac->alg = alg;
164     hmac->opaque = ctx;
165
166     return hmac;
167 }
This page took 0.033549 seconds and 4 git commands to generate.