]>
Commit | Line | Data |
---|---|---|
12a4f216 LM |
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" | |
14a5a2ae | 18 | #include "hmacpriv.h" |
12a4f216 LM |
19 | #include <gcrypt.h> |
20 | ||
5ce9cfe7 LM |
21 | static 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 | ||
31 | typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; | |
32 | struct QCryptoHmacGcrypt { | |
33 | gcry_mac_hd_t handle; | |
34 | }; | |
35 | ||
12a4f216 LM |
36 | bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) |
37 | { | |
5ce9cfe7 LM |
38 | if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && |
39 | qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) { | |
40 | return true; | |
41 | } | |
42 | ||
12a4f216 LM |
43 | return false; |
44 | } | |
45 | ||
14a5a2ae LM |
46 | void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg, |
47 | const uint8_t *key, size_t nkey, | |
48 | Error **errp) | |
12a4f216 | 49 | { |
5ce9cfe7 LM |
50 | QCryptoHmacGcrypt *ctx; |
51 | gcry_error_t err; | |
52 | ||
53 | if (!qcrypto_hmac_supports(alg)) { | |
54 | error_setg(errp, "Unsupported hmac algorithm %s", | |
977c736f | 55 | QCryptoHashAlgorithm_str(alg)); |
5ce9cfe7 LM |
56 | return NULL; |
57 | } | |
58 | ||
5ce9cfe7 LM |
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)); | |
822d15de | 73 | gcry_mac_close(ctx->handle); |
5ce9cfe7 LM |
74 | goto error; |
75 | } | |
76 | ||
822d15de | 77 | return ctx; |
5ce9cfe7 LM |
78 | |
79 | error: | |
80 | g_free(ctx); | |
12a4f216 LM |
81 | return NULL; |
82 | } | |
83 | ||
14a5a2ae LM |
84 | static void |
85 | qcrypto_gcrypt_hmac_ctx_free(QCryptoHmac *hmac) | |
12a4f216 | 86 | { |
5ce9cfe7 LM |
87 | QCryptoHmacGcrypt *ctx; |
88 | ||
5ce9cfe7 LM |
89 | ctx = hmac->opaque; |
90 | gcry_mac_close(ctx->handle); | |
91 | ||
92 | g_free(ctx); | |
12a4f216 LM |
93 | } |
94 | ||
14a5a2ae LM |
95 | static int |
96 | qcrypto_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) | |
12a4f216 | 102 | { |
5ce9cfe7 LM |
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; | |
12a4f216 | 145 | } |
822d15de | 146 | |
14a5a2ae LM |
147 | QCryptoHmacDriver qcrypto_hmac_lib_driver = { |
148 | .hmac_bytesv = qcrypto_gcrypt_hmac_bytesv, | |
149 | .hmac_free = qcrypto_gcrypt_hmac_ctx_free, | |
150 | }; |