xref: /qemu/crypto/hash-nettle.c (revision dde538c9)
1 /*
2  * QEMU Crypto hash algorithms
3  *
4  * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
5  * Copyright (c) 2016 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 "crypto/hash.h"
25 #include "hashpriv.h"
26 #include <nettle/md5.h>
27 #include <nettle/sha.h>
28 #include <nettle/ripemd160.h>
29 
30 typedef void (*qcrypto_nettle_init)(void *ctx);
31 typedef void (*qcrypto_nettle_write)(void *ctx,
32                                      size_t len,
33                                      const uint8_t *buf);
34 typedef void (*qcrypto_nettle_result)(void *ctx,
35                                       size_t len,
36                                       uint8_t *buf);
37 
38 union qcrypto_hash_ctx {
39     struct md5_ctx md5;
40     struct sha1_ctx sha1;
41     struct sha224_ctx sha224;
42     struct sha256_ctx sha256;
43     struct sha384_ctx sha384;
44     struct sha512_ctx sha512;
45     struct ripemd160_ctx ripemd160;
46 };
47 
48 struct qcrypto_hash_alg {
49     qcrypto_nettle_init init;
50     qcrypto_nettle_write write;
51     qcrypto_nettle_result result;
52     size_t len;
53 } qcrypto_hash_alg_map[] = {
54     [QCRYPTO_HASH_ALGO_MD5] = {
55         .init = (qcrypto_nettle_init)md5_init,
56         .write = (qcrypto_nettle_write)md5_update,
57         .result = (qcrypto_nettle_result)md5_digest,
58         .len = MD5_DIGEST_SIZE,
59     },
60     [QCRYPTO_HASH_ALGO_SHA1] = {
61         .init = (qcrypto_nettle_init)sha1_init,
62         .write = (qcrypto_nettle_write)sha1_update,
63         .result = (qcrypto_nettle_result)sha1_digest,
64         .len = SHA1_DIGEST_SIZE,
65     },
66     [QCRYPTO_HASH_ALGO_SHA224] = {
67         .init = (qcrypto_nettle_init)sha224_init,
68         .write = (qcrypto_nettle_write)sha224_update,
69         .result = (qcrypto_nettle_result)sha224_digest,
70         .len = SHA224_DIGEST_SIZE,
71     },
72     [QCRYPTO_HASH_ALGO_SHA256] = {
73         .init = (qcrypto_nettle_init)sha256_init,
74         .write = (qcrypto_nettle_write)sha256_update,
75         .result = (qcrypto_nettle_result)sha256_digest,
76         .len = SHA256_DIGEST_SIZE,
77     },
78     [QCRYPTO_HASH_ALGO_SHA384] = {
79         .init = (qcrypto_nettle_init)sha384_init,
80         .write = (qcrypto_nettle_write)sha384_update,
81         .result = (qcrypto_nettle_result)sha384_digest,
82         .len = SHA384_DIGEST_SIZE,
83     },
84     [QCRYPTO_HASH_ALGO_SHA512] = {
85         .init = (qcrypto_nettle_init)sha512_init,
86         .write = (qcrypto_nettle_write)sha512_update,
87         .result = (qcrypto_nettle_result)sha512_digest,
88         .len = SHA512_DIGEST_SIZE,
89     },
90     [QCRYPTO_HASH_ALGO_RIPEMD160] = {
91         .init = (qcrypto_nettle_init)ripemd160_init,
92         .write = (qcrypto_nettle_write)ripemd160_update,
93         .result = (qcrypto_nettle_result)ripemd160_digest,
94         .len = RIPEMD160_DIGEST_SIZE,
95     },
96 };
97 
98 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
99 {
100     if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
101         qcrypto_hash_alg_map[alg].init != NULL) {
102         return true;
103     }
104     return false;
105 }
106 
107 static
108 QCryptoHash *qcrypto_nettle_hash_new(QCryptoHashAlgo alg, Error **errp)
109 {
110     QCryptoHash *hash;
111 
112     hash = g_new(QCryptoHash, 1);
113     hash->alg = alg;
114     hash->opaque = g_new(union qcrypto_hash_ctx, 1);
115 
116     qcrypto_hash_alg_map[alg].init(hash->opaque);
117     return hash;
118 }
119 
120 static
121 void qcrypto_nettle_hash_free(QCryptoHash *hash)
122 {
123     union qcrypto_hash_ctx *ctx = hash->opaque;
124 
125     g_free(ctx);
126     g_free(hash);
127 }
128 
129 static
130 int qcrypto_nettle_hash_update(QCryptoHash *hash,
131                                const struct iovec *iov,
132                                size_t niov,
133                                Error **errp)
134 {
135     union qcrypto_hash_ctx *ctx = hash->opaque;
136 
137     for (int i = 0; i < niov; i++) {
138         qcrypto_hash_alg_map[hash->alg].write(ctx,
139                                               iov[i].iov_len,
140                                               iov[i].iov_base);
141     }
142 
143     return 0;
144 }
145 
146 static
147 int qcrypto_nettle_hash_finalize(QCryptoHash *hash,
148                                  uint8_t **result,
149                                  size_t *result_len,
150                                  Error **errp)
151 {
152     union qcrypto_hash_ctx *ctx = hash->opaque;
153     int ret = qcrypto_hash_alg_map[hash->alg].len;
154 
155     if (*result_len == 0) {
156         *result_len = ret;
157         *result = g_new(uint8_t, *result_len);
158     } else if (*result_len != ret) {
159         error_setg(errp,
160                    "Result buffer size %zu is smaller than hash %d",
161                    *result_len, ret);
162         return -1;
163     }
164 
165     qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result);
166 
167     return 0;
168 }
169 
170 QCryptoHashDriver qcrypto_hash_lib_driver = {
171     .hash_new      = qcrypto_nettle_hash_new,
172     .hash_update   = qcrypto_nettle_hash_update,
173     .hash_finalize = qcrypto_nettle_hash_finalize,
174     .hash_free     = qcrypto_nettle_hash_free,
175 };
176