]> git.proxmox.com Git - mirror_qemu.git/blob - crypto/cipher-builtin.c.inc
Merge tag 'pull-vfio-20240129' of https://github.com/legoater/qemu into staging
[mirror_qemu.git] / crypto / cipher-builtin.c.inc
1 /*
2 * QEMU Crypto cipher built-in algorithms
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "crypto/aes.h"
22
23 typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
24 struct QCryptoCipherBuiltinAESContext {
25 AES_KEY enc;
26 AES_KEY dec;
27 };
28
29 typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
30 struct QCryptoCipherBuiltinAES {
31 QCryptoCipher base;
32 QCryptoCipherBuiltinAESContext key;
33 uint8_t iv[AES_BLOCK_SIZE];
34 };
35
36
37 static inline bool qcrypto_length_check(size_t len, size_t blocksize,
38 Error **errp)
39 {
40 if (unlikely(len & (blocksize - 1))) {
41 error_setg(errp, "Length %zu must be a multiple of block size %zu",
42 len, blocksize);
43 return false;
44 }
45 return true;
46 }
47
48 static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
49 {
50 g_free(cipher);
51 }
52
53 static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
54 const uint8_t *iv, size_t niv,
55 Error **errp)
56 {
57 error_setg(errp, "Setting IV is not supported");
58 return -1;
59 }
60
61 static void do_aes_encrypt_ecb(const void *vctx,
62 size_t len,
63 uint8_t *out,
64 const uint8_t *in)
65 {
66 const QCryptoCipherBuiltinAESContext *ctx = vctx;
67
68 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
69 while (len) {
70 AES_encrypt(in, out, &ctx->enc);
71 in += AES_BLOCK_SIZE;
72 out += AES_BLOCK_SIZE;
73 len -= AES_BLOCK_SIZE;
74 }
75 }
76
77 static void do_aes_decrypt_ecb(const void *vctx,
78 size_t len,
79 uint8_t *out,
80 const uint8_t *in)
81 {
82 const QCryptoCipherBuiltinAESContext *ctx = vctx;
83
84 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
85 while (len) {
86 AES_decrypt(in, out, &ctx->dec);
87 in += AES_BLOCK_SIZE;
88 out += AES_BLOCK_SIZE;
89 len -= AES_BLOCK_SIZE;
90 }
91 }
92
93 static void do_aes_encrypt_cbc(const AES_KEY *key,
94 size_t len,
95 uint8_t *out,
96 const uint8_t *in,
97 uint8_t *ivec)
98 {
99 uint8_t tmp[AES_BLOCK_SIZE];
100 size_t n;
101
102 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
103 while (len) {
104 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
105 tmp[n] = in[n] ^ ivec[n];
106 }
107 AES_encrypt(tmp, out, key);
108 memcpy(ivec, out, AES_BLOCK_SIZE);
109 len -= AES_BLOCK_SIZE;
110 in += AES_BLOCK_SIZE;
111 out += AES_BLOCK_SIZE;
112 }
113 }
114
115 static void do_aes_decrypt_cbc(const AES_KEY *key,
116 size_t len,
117 uint8_t *out,
118 const uint8_t *in,
119 uint8_t *ivec)
120 {
121 uint8_t tmp[AES_BLOCK_SIZE];
122 size_t n;
123
124 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
125 while (len) {
126 memcpy(tmp, in, AES_BLOCK_SIZE);
127 AES_decrypt(in, out, key);
128 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
129 out[n] ^= ivec[n];
130 }
131 memcpy(ivec, tmp, AES_BLOCK_SIZE);
132 len -= AES_BLOCK_SIZE;
133 in += AES_BLOCK_SIZE;
134 out += AES_BLOCK_SIZE;
135 }
136 }
137
138 static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
139 const void *in, void *out,
140 size_t len, Error **errp)
141 {
142 QCryptoCipherBuiltinAES *ctx
143 = container_of(cipher, QCryptoCipherBuiltinAES, base);
144
145 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
146 return -1;
147 }
148 do_aes_encrypt_ecb(&ctx->key, len, out, in);
149 return 0;
150 }
151
152 static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
153 const void *in, void *out,
154 size_t len, Error **errp)
155 {
156 QCryptoCipherBuiltinAES *ctx
157 = container_of(cipher, QCryptoCipherBuiltinAES, base);
158
159 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
160 return -1;
161 }
162 do_aes_decrypt_ecb(&ctx->key, len, out, in);
163 return 0;
164 }
165
166 static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
167 const void *in, void *out,
168 size_t len, Error **errp)
169 {
170 QCryptoCipherBuiltinAES *ctx
171 = container_of(cipher, QCryptoCipherBuiltinAES, base);
172
173 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
174 return -1;
175 }
176 do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
177 return 0;
178 }
179
180 static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
181 const void *in, void *out,
182 size_t len, Error **errp)
183 {
184 QCryptoCipherBuiltinAES *ctx
185 = container_of(cipher, QCryptoCipherBuiltinAES, base);
186
187 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
188 return -1;
189 }
190 do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
191 return 0;
192 }
193
194 static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
195 size_t niv, Error **errp)
196 {
197 QCryptoCipherBuiltinAES *ctx
198 = container_of(cipher, QCryptoCipherBuiltinAES, base);
199
200 if (niv != AES_BLOCK_SIZE) {
201 error_setg(errp, "IV must be %d bytes not %zu",
202 AES_BLOCK_SIZE, niv);
203 return -1;
204 }
205
206 memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
207 return 0;
208 }
209
210 static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = {
211 .cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb,
212 .cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb,
213 .cipher_setiv = qcrypto_cipher_no_setiv,
214 .cipher_free = qcrypto_cipher_ctx_free,
215 };
216
217 static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
218 .cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc,
219 .cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc,
220 .cipher_setiv = qcrypto_cipher_aes_setiv,
221 .cipher_free = qcrypto_cipher_ctx_free,
222 };
223
224 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
225 QCryptoCipherMode mode)
226 {
227 switch (alg) {
228 case QCRYPTO_CIPHER_ALG_AES_128:
229 case QCRYPTO_CIPHER_ALG_AES_192:
230 case QCRYPTO_CIPHER_ALG_AES_256:
231 switch (mode) {
232 case QCRYPTO_CIPHER_MODE_ECB:
233 case QCRYPTO_CIPHER_MODE_CBC:
234 return true;
235 default:
236 return false;
237 }
238 break;
239 default:
240 return false;
241 }
242 }
243
244 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
245 QCryptoCipherMode mode,
246 const uint8_t *key,
247 size_t nkey,
248 Error **errp)
249 {
250 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
251 return NULL;
252 }
253
254 switch (alg) {
255 case QCRYPTO_CIPHER_ALG_AES_128:
256 case QCRYPTO_CIPHER_ALG_AES_192:
257 case QCRYPTO_CIPHER_ALG_AES_256:
258 {
259 QCryptoCipherBuiltinAES *ctx;
260 const QCryptoCipherDriver *drv;
261
262 switch (mode) {
263 case QCRYPTO_CIPHER_MODE_ECB:
264 drv = &qcrypto_cipher_aes_driver_ecb;
265 break;
266 case QCRYPTO_CIPHER_MODE_CBC:
267 drv = &qcrypto_cipher_aes_driver_cbc;
268 break;
269 default:
270 goto bad_mode;
271 }
272
273 ctx = g_new0(QCryptoCipherBuiltinAES, 1);
274 ctx->base.driver = drv;
275
276 if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
277 error_setg(errp, "Failed to set encryption key");
278 goto error;
279 }
280 if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
281 error_setg(errp, "Failed to set decryption key");
282 goto error;
283 }
284
285 return &ctx->base;
286
287 error:
288 g_free(ctx);
289 return NULL;
290 }
291
292 default:
293 error_setg(errp,
294 "Unsupported cipher algorithm %s",
295 QCryptoCipherAlgorithm_str(alg));
296 return NULL;
297 }
298
299 bad_mode:
300 error_setg(errp, "Unsupported cipher mode %s",
301 QCryptoCipherMode_str(mode));
302 return NULL;
303 }