]>
Commit | Line | Data |
---|---|---|
12a4f216 LM |
1 | /* |
2 | * QEMU Crypto hmac algorithms (based on nettle) | |
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 <nettle/hmac.h> |
20 | ||
f8878490 DB |
21 | #if CONFIG_NETTLE_VERSION_MAJOR < 3 |
22 | typedef unsigned int hmac_length_t; | |
23 | #else | |
24 | typedef size_t hmac_length_t; | |
25 | #endif | |
26 | ||
f4d76747 | 27 | typedef void (*qcrypto_nettle_hmac_setkey)(void *ctx, |
f8878490 DB |
28 | hmac_length_t key_length, |
29 | const uint8_t *key); | |
f4d76747 LM |
30 | |
31 | typedef void (*qcrypto_nettle_hmac_update)(void *ctx, | |
f8878490 DB |
32 | hmac_length_t length, |
33 | const uint8_t *data); | |
f4d76747 LM |
34 | |
35 | typedef void (*qcrypto_nettle_hmac_digest)(void *ctx, | |
f8878490 DB |
36 | hmac_length_t length, |
37 | uint8_t *digest); | |
f4d76747 LM |
38 | |
39 | typedef struct QCryptoHmacNettle QCryptoHmacNettle; | |
40 | struct QCryptoHmacNettle { | |
41 | union qcrypto_nettle_hmac_ctx { | |
42 | struct hmac_md5_ctx md5_ctx; | |
43 | struct hmac_sha1_ctx sha1_ctx; | |
44 | struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */ | |
45 | struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */ | |
46 | struct hmac_ripemd160_ctx ripemd160_ctx; | |
47 | } u; | |
48 | }; | |
49 | ||
50 | struct qcrypto_nettle_hmac_alg { | |
51 | qcrypto_nettle_hmac_setkey setkey; | |
52 | qcrypto_nettle_hmac_update update; | |
53 | qcrypto_nettle_hmac_digest digest; | |
54 | size_t len; | |
55 | } qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = { | |
56 | [QCRYPTO_HASH_ALG_MD5] = { | |
57 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_md5_set_key, | |
58 | .update = (qcrypto_nettle_hmac_update)hmac_md5_update, | |
59 | .digest = (qcrypto_nettle_hmac_digest)hmac_md5_digest, | |
60 | .len = MD5_DIGEST_SIZE, | |
61 | }, | |
62 | [QCRYPTO_HASH_ALG_SHA1] = { | |
63 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha1_set_key, | |
64 | .update = (qcrypto_nettle_hmac_update)hmac_sha1_update, | |
65 | .digest = (qcrypto_nettle_hmac_digest)hmac_sha1_digest, | |
66 | .len = SHA1_DIGEST_SIZE, | |
67 | }, | |
68 | [QCRYPTO_HASH_ALG_SHA224] = { | |
69 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha224_set_key, | |
70 | .update = (qcrypto_nettle_hmac_update)hmac_sha224_update, | |
71 | .digest = (qcrypto_nettle_hmac_digest)hmac_sha224_digest, | |
72 | .len = SHA224_DIGEST_SIZE, | |
73 | }, | |
74 | [QCRYPTO_HASH_ALG_SHA256] = { | |
75 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha256_set_key, | |
76 | .update = (qcrypto_nettle_hmac_update)hmac_sha256_update, | |
77 | .digest = (qcrypto_nettle_hmac_digest)hmac_sha256_digest, | |
78 | .len = SHA256_DIGEST_SIZE, | |
79 | }, | |
80 | [QCRYPTO_HASH_ALG_SHA384] = { | |
81 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha384_set_key, | |
82 | .update = (qcrypto_nettle_hmac_update)hmac_sha384_update, | |
83 | .digest = (qcrypto_nettle_hmac_digest)hmac_sha384_digest, | |
84 | .len = SHA384_DIGEST_SIZE, | |
85 | }, | |
86 | [QCRYPTO_HASH_ALG_SHA512] = { | |
87 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_sha512_set_key, | |
88 | .update = (qcrypto_nettle_hmac_update)hmac_sha512_update, | |
89 | .digest = (qcrypto_nettle_hmac_digest)hmac_sha512_digest, | |
90 | .len = SHA512_DIGEST_SIZE, | |
91 | }, | |
92 | [QCRYPTO_HASH_ALG_RIPEMD160] = { | |
93 | .setkey = (qcrypto_nettle_hmac_setkey)hmac_ripemd160_set_key, | |
94 | .update = (qcrypto_nettle_hmac_update)hmac_ripemd160_update, | |
95 | .digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest, | |
96 | .len = RIPEMD160_DIGEST_SIZE, | |
97 | }, | |
98 | }; | |
99 | ||
12a4f216 LM |
100 | bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) |
101 | { | |
f4d76747 LM |
102 | if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && |
103 | qcrypto_hmac_alg_map[alg].setkey != NULL) { | |
104 | return true; | |
105 | } | |
106 | ||
12a4f216 LM |
107 | return false; |
108 | } | |
109 | ||
14a5a2ae LM |
110 | void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg, |
111 | const uint8_t *key, size_t nkey, | |
112 | Error **errp) | |
12a4f216 | 113 | { |
f4d76747 LM |
114 | QCryptoHmacNettle *ctx; |
115 | ||
116 | if (!qcrypto_hmac_supports(alg)) { | |
117 | error_setg(errp, "Unsupported hmac algorithm %s", | |
977c736f | 118 | QCryptoHashAlgorithm_str(alg)); |
f4d76747 LM |
119 | return NULL; |
120 | } | |
121 | ||
f4d76747 LM |
122 | ctx = g_new0(QCryptoHmacNettle, 1); |
123 | ||
124 | qcrypto_hmac_alg_map[alg].setkey(&ctx->u, nkey, key); | |
125 | ||
8c2776d8 | 126 | return ctx; |
12a4f216 LM |
127 | } |
128 | ||
14a5a2ae LM |
129 | static void |
130 | qcrypto_nettle_hmac_ctx_free(QCryptoHmac *hmac) | |
12a4f216 | 131 | { |
f4d76747 LM |
132 | QCryptoHmacNettle *ctx; |
133 | ||
f4d76747 | 134 | ctx = hmac->opaque; |
f4d76747 | 135 | g_free(ctx); |
12a4f216 LM |
136 | } |
137 | ||
14a5a2ae LM |
138 | static int |
139 | qcrypto_nettle_hmac_bytesv(QCryptoHmac *hmac, | |
140 | const struct iovec *iov, | |
141 | size_t niov, | |
142 | uint8_t **result, | |
143 | size_t *resultlen, | |
144 | Error **errp) | |
12a4f216 | 145 | { |
f4d76747 | 146 | QCryptoHmacNettle *ctx; |
f8878490 | 147 | size_t i; |
f4d76747 LM |
148 | |
149 | ctx = (QCryptoHmacNettle *)hmac->opaque; | |
150 | ||
151 | for (i = 0; i < niov; ++i) { | |
152 | size_t len = iov[i].iov_len; | |
153 | uint8_t *base = iov[i].iov_base; | |
154 | while (len) { | |
155 | size_t shortlen = MIN(len, UINT_MAX); | |
156 | qcrypto_hmac_alg_map[hmac->alg].update(&ctx->u, len, base); | |
157 | len -= shortlen; | |
158 | base += len; | |
159 | } | |
160 | } | |
161 | ||
162 | if (*resultlen == 0) { | |
163 | *resultlen = qcrypto_hmac_alg_map[hmac->alg].len; | |
164 | *result = g_new0(uint8_t, *resultlen); | |
165 | } else if (*resultlen != qcrypto_hmac_alg_map[hmac->alg].len) { | |
166 | error_setg(errp, | |
167 | "Result buffer size %zu is smaller than hash %zu", | |
168 | *resultlen, qcrypto_hmac_alg_map[hmac->alg].len); | |
169 | return -1; | |
170 | } | |
171 | ||
172 | qcrypto_hmac_alg_map[hmac->alg].digest(&ctx->u, *resultlen, *result); | |
173 | ||
174 | return 0; | |
12a4f216 | 175 | } |
8c2776d8 | 176 | |
14a5a2ae LM |
177 | QCryptoHmacDriver qcrypto_hmac_lib_driver = { |
178 | .hmac_bytesv = qcrypto_nettle_hmac_bytesv, | |
179 | .hmac_free = qcrypto_nettle_hmac_ctx_free, | |
180 | }; |