]> git.proxmox.com Git - mirror_qemu.git/blame - 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
CommitLineData
ca38a4cc
DB
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
b7cbb874 9 * version 2.1 of the License, or (at your option) any later version.
ca38a4cc
DB
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"
ca38a4cc 22
e3ba0b67
DB
23typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
24struct QCryptoCipherBuiltinAESContext {
25 AES_KEY enc;
26 AES_KEY dec;
27};
a3db31b8 28
ca38a4cc
DB
29typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
30struct QCryptoCipherBuiltinAES {
a3db31b8 31 QCryptoCipher base;
e3ba0b67 32 QCryptoCipherBuiltinAESContext key;
eb2a770b 33 uint8_t iv[AES_BLOCK_SIZE];
ca38a4cc 34};
ca38a4cc 35
ca38a4cc 36
a3db31b8
RH
37static 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}
ca38a4cc 47
a3db31b8 48static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
ca38a4cc 49{
3eedf5cc 50 g_free(cipher);
ca38a4cc
DB
51}
52
a3db31b8
RH
53static 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
8ee47cdd
RH
61static void do_aes_encrypt_ecb(const void *vctx,
62 size_t len,
63 uint8_t *out,
64 const uint8_t *in)
e3ba0b67 65{
8ee47cdd 66 const QCryptoCipherBuiltinAESContext *ctx = vctx;
838e4631
RH
67
68 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
e3ba0b67 69 while (len) {
8ee47cdd
RH
70 AES_encrypt(in, out, &ctx->enc);
71 in += AES_BLOCK_SIZE;
72 out += AES_BLOCK_SIZE;
838e4631 73 len -= AES_BLOCK_SIZE;
e3ba0b67
DB
74 }
75}
76
8ee47cdd
RH
77static void do_aes_decrypt_ecb(const void *vctx,
78 size_t len,
79 uint8_t *out,
80 const uint8_t *in)
e3ba0b67 81{
8ee47cdd 82 const QCryptoCipherBuiltinAESContext *ctx = vctx;
838e4631
RH
83
84 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
e3ba0b67 85 while (len) {
8ee47cdd
RH
86 AES_decrypt(in, out, &ctx->dec);
87 in += AES_BLOCK_SIZE;
88 out += AES_BLOCK_SIZE;
838e4631 89 len -= AES_BLOCK_SIZE;
e3ba0b67
DB
90 }
91}
92
ef186f4b
RH
93static 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)
a2d76b6b 98{
ef186f4b
RH
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];
a2d76b6b 106 }
ef186f4b
RH
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;
a2d76b6b
RH
112 }
113}
114
ef186f4b
RH
115static 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}
a2d76b6b 137
a3db31b8
RH
138static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
139 const void *in, void *out,
140 size_t len, Error **errp)
ca38a4cc 141{
a3db31b8
RH
142 QCryptoCipherBuiltinAES *ctx
143 = container_of(cipher, QCryptoCipherBuiltinAES, base);
ca38a4cc 144
a3db31b8
RH
145 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
146 return -1;
ca38a4cc 147 }
a3db31b8 148 do_aes_encrypt_ecb(&ctx->key, len, out, in);
ca38a4cc
DB
149 return 0;
150}
151
a3db31b8
RH
152static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
153 const void *in, void *out,
154 size_t len, Error **errp)
ca38a4cc 155{
a3db31b8
RH
156 QCryptoCipherBuiltinAES *ctx
157 = container_of(cipher, QCryptoCipherBuiltinAES, base);
ca38a4cc 158
a3db31b8
RH
159 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
160 return -1;
ca38a4cc 161 }
a3db31b8 162 do_aes_decrypt_ecb(&ctx->key, len, out, in);
ca38a4cc
DB
163 return 0;
164}
165
a3db31b8
RH
166static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
167 const void *in, void *out,
168 size_t len, Error **errp)
ca38a4cc 169{
a3db31b8
RH
170 QCryptoCipherBuiltinAES *ctx
171 = container_of(cipher, QCryptoCipherBuiltinAES, base);
3eedf5cc 172
a3db31b8 173 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
ca38a4cc
DB
174 return -1;
175 }
a3db31b8 176 do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
ca38a4cc
DB
177 return 0;
178}
179
a3db31b8
RH
180static 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);
ca38a4cc 186
a3db31b8
RH
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}
ca38a4cc 193
a3db31b8
RH
194static 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);
eaec903c 199
a3db31b8
RH
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;
ca38a4cc
DB
204 }
205
a3db31b8
RH
206 memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
207 return 0;
208}
ca38a4cc 209
a3db31b8
RH
210static 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};
ca38a4cc 216
a3db31b8
RH
217static 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};
ca38a4cc 223
f844836d
GA
224bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
225 QCryptoCipherMode mode)
ca38a4cc
DB
226{
227 switch (alg) {
ca38a4cc
DB
228 case QCRYPTO_CIPHER_ALG_AES_128:
229 case QCRYPTO_CIPHER_ALG_AES_192:
230 case QCRYPTO_CIPHER_ALG_AES_256:
a3db31b8
RH
231 switch (mode) {
232 case QCRYPTO_CIPHER_MODE_ECB:
233 case QCRYPTO_CIPHER_MODE_CBC:
a3db31b8
RH
234 return true;
235 default:
236 return false;
237 }
f844836d
GA
238 break;
239 default:
240 return false;
241 }
ca38a4cc
DB
242}
243
3eedf5cc
RH
244static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
245 QCryptoCipherMode mode,
246 const uint8_t *key,
247 size_t nkey,
248 Error **errp)
ca38a4cc 249{
eaec903c 250 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
d962c626 251 return NULL;
ca38a4cc
DB
252 }
253
d962c626 254 switch (alg) {
ca38a4cc
DB
255 case QCRYPTO_CIPHER_ALG_AES_128:
256 case QCRYPTO_CIPHER_ALG_AES_192:
257 case QCRYPTO_CIPHER_ALG_AES_256:
a3db31b8
RH
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;
a3db31b8
RH
269 default:
270 goto bad_mode;
271 }
272
273 ctx = g_new0(QCryptoCipherBuiltinAES, 1);
274 ctx->base.driver = drv;
275
a3db31b8
RH
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
ca38a4cc
DB
292 default:
293 error_setg(errp,
90d6f60d 294 "Unsupported cipher algorithm %s",
977c736f 295 QCryptoCipherAlgorithm_str(alg));
d962c626 296 return NULL;
ca38a4cc 297 }
ca38a4cc 298
a3db31b8
RH
299 bad_mode:
300 error_setg(errp, "Unsupported cipher mode %s",
301 QCryptoCipherMode_str(mode));
302 return NULL;
ca38a4cc 303}