xref: /openbmc/qemu/crypto/hash.c (revision ca5aa28e)
1 /*
2  * QEMU Crypto hash algorithms
3  *
4  * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
5  * Copyright (c) 2015 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "qemu/osdep.h"
23 #include "qapi/error.h"
24 #include "qapi-types-crypto.h"
25 #include "crypto/hash.h"
26 #include "hashpriv.h"
27 
28 static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALGO__MAX] = {
29     [QCRYPTO_HASH_ALGO_MD5]       = QCRYPTO_HASH_DIGEST_LEN_MD5,
30     [QCRYPTO_HASH_ALGO_SHA1]      = QCRYPTO_HASH_DIGEST_LEN_SHA1,
31     [QCRYPTO_HASH_ALGO_SHA224]    = QCRYPTO_HASH_DIGEST_LEN_SHA224,
32     [QCRYPTO_HASH_ALGO_SHA256]    = QCRYPTO_HASH_DIGEST_LEN_SHA256,
33     [QCRYPTO_HASH_ALGO_SHA384]    = QCRYPTO_HASH_DIGEST_LEN_SHA384,
34     [QCRYPTO_HASH_ALGO_SHA512]    = QCRYPTO_HASH_DIGEST_LEN_SHA512,
35     [QCRYPTO_HASH_ALGO_RIPEMD160] = QCRYPTO_HASH_DIGEST_LEN_RIPEMD160,
36 };
37 
38 size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg)
39 {
40     assert(alg < G_N_ELEMENTS(qcrypto_hash_alg_size));
41     return qcrypto_hash_alg_size[alg];
42 }
43 
44 int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
45                         const struct iovec *iov,
46                         size_t niov,
47                         uint8_t **result,
48                         size_t *resultlen,
49                         Error **errp)
50 {
51     g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
52 
53     if (!ctx) {
54         return -1;
55     }
56 
57     if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
58         qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) {
59         return -1;
60     }
61 
62     return 0;
63 }
64 
65 
66 int qcrypto_hash_bytes(QCryptoHashAlgo alg,
67                        const char *buf,
68                        size_t len,
69                        uint8_t **result,
70                        size_t *resultlen,
71                        Error **errp)
72 {
73     struct iovec iov = { .iov_base = (char *)buf,
74                          .iov_len = len };
75     return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
76 }
77 
78 int qcrypto_hash_updatev(QCryptoHash *hash,
79                          const struct iovec *iov,
80                          size_t niov,
81                          Error **errp)
82 {
83     QCryptoHashDriver *drv = hash->driver;
84 
85     return drv->hash_update(hash, iov, niov, errp);
86 }
87 
88 int qcrypto_hash_update(QCryptoHash *hash,
89                         const char *buf,
90                         size_t len,
91                         Error **errp)
92 {
93     struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
94 
95     return qcrypto_hash_updatev(hash, &iov, 1, errp);
96 }
97 
98 QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp)
99 {
100     QCryptoHash *hash = NULL;
101 
102     if (!qcrypto_hash_supports(alg)) {
103         error_setg(errp, "Unsupported hash algorithm %s",
104                    QCryptoHashAlgo_str(alg));
105         return NULL;
106    }
107 
108 #ifdef CONFIG_AF_ALG
109     hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL);
110     if (hash) {
111         hash->driver = &qcrypto_hash_afalg_driver;
112         return hash;
113     }
114 #endif
115 
116     hash = qcrypto_hash_lib_driver.hash_new(alg, errp);
117     if (!hash) {
118         return NULL;
119     }
120 
121     hash->driver = &qcrypto_hash_lib_driver;
122     return hash;
123 }
124 
125 void qcrypto_hash_free(QCryptoHash *hash)
126 {
127    QCryptoHashDriver *drv;
128 
129     if (hash) {
130         drv = hash->driver;
131         drv->hash_free(hash);
132     }
133 }
134 
135 int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
136                                 uint8_t **result,
137                                 size_t *result_len,
138                                 Error **errp)
139 {
140     QCryptoHashDriver *drv = hash->driver;
141 
142     return drv->hash_finalize(hash, result, result_len, errp);
143 }
144 
145 static const char hex[] = "0123456789abcdef";
146 
147 int qcrypto_hash_finalize_digest(QCryptoHash *hash,
148                                  char **digest,
149                                  Error **errp)
150 {
151     int ret;
152     g_autofree uint8_t *result = NULL;
153     size_t resultlen = 0;
154     size_t i;
155 
156     ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
157     if (ret == 0) {
158         *digest = g_new0(char, (resultlen * 2) + 1);
159         for (i = 0 ; i < resultlen ; i++) {
160             (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
161             (*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
162         }
163         (*digest)[resultlen * 2] = '\0';
164     }
165 
166     return ret;
167 }
168 
169 int qcrypto_hash_finalize_base64(QCryptoHash *hash,
170                                  char **base64,
171                                  Error **errp)
172 {
173     int ret;
174     g_autofree uint8_t *result = NULL;
175     size_t resultlen = 0;
176 
177     ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
178     if (ret == 0) {
179         *base64 = g_base64_encode(result, resultlen);
180     }
181 
182     return ret;
183 }
184 
185 int qcrypto_hash_digestv(QCryptoHashAlgo alg,
186                          const struct iovec *iov,
187                          size_t niov,
188                          char **digest,
189                          Error **errp)
190 {
191     g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
192 
193     if (!ctx) {
194         return -1;
195     }
196 
197     if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
198         qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) {
199         return -1;
200     }
201 
202     return 0;
203 }
204 
205 int qcrypto_hash_digest(QCryptoHashAlgo alg,
206                         const char *buf,
207                         size_t len,
208                         char **digest,
209                         Error **errp)
210 {
211     struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
212 
213     return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
214 }
215 
216 int qcrypto_hash_base64v(QCryptoHashAlgo alg,
217                          const struct iovec *iov,
218                          size_t niov,
219                          char **base64,
220                          Error **errp)
221 {
222     g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
223 
224     if (!ctx) {
225         return -1;
226     }
227 
228     if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
229         qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) {
230         return -1;
231     }
232 
233     return 0;
234 }
235 
236 int qcrypto_hash_base64(QCryptoHashAlgo alg,
237                         const char *buf,
238                         size_t len,
239                         char **base64,
240                         Error **errp)
241 {
242     struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
243 
244     return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
245 }
246