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