blob: 7597cf4a10fd208664c7082240bba49f4fc38a0d [file] [log] [blame]
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +01001/*
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
Thomas Huthb7cbb872019-02-13 16:54:59 +01009 * version 2.1 of the License, or (at your option) any later version.
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010010 *
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#include "crypto/desrfb.h"
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000023#include "crypto/xts.h"
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010024
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000025typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
26struct QCryptoCipherBuiltinAESContext {
27 AES_KEY enc;
28 AES_KEY dec;
29};
Richard Hendersona3db31b2020-08-28 10:05:21 -070030
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010031typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
32struct QCryptoCipherBuiltinAES {
Richard Hendersona3db31b2020-08-28 10:05:21 -070033 QCryptoCipher base;
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000034 QCryptoCipherBuiltinAESContext key;
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000035 QCryptoCipherBuiltinAESContext key_tweak;
Daniel P. Berrangeeb2a7702015-10-16 13:23:13 +010036 uint8_t iv[AES_BLOCK_SIZE];
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010037};
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010038
39
Richard Hendersona3db31b2020-08-28 10:05:21 -070040static inline bool qcrypto_length_check(size_t len, size_t blocksize,
41 Error **errp)
42{
43 if (unlikely(len & (blocksize - 1))) {
44 error_setg(errp, "Length %zu must be a multiple of block size %zu",
45 len, blocksize);
46 return false;
47 }
48 return true;
49}
50
51static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010052{
Richard Henderson3eedf5c2020-08-28 10:05:14 -070053 g_free(cipher);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +010054}
55
Richard Hendersona3db31b2020-08-28 10:05:21 -070056static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
57 const uint8_t *iv, size_t niv,
58 Error **errp)
59{
60 error_setg(errp, "Setting IV is not supported");
61 return -1;
62}
63
Richard Henderson8ee47cd2020-08-28 10:05:18 -070064static void do_aes_encrypt_ecb(const void *vctx,
65 size_t len,
66 uint8_t *out,
67 const uint8_t *in)
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000068{
Richard Henderson8ee47cd2020-08-28 10:05:18 -070069 const QCryptoCipherBuiltinAESContext *ctx = vctx;
Richard Henderson838e4632020-08-28 10:05:17 -070070
71 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000072 while (len) {
Richard Henderson8ee47cd2020-08-28 10:05:18 -070073 AES_encrypt(in, out, &ctx->enc);
74 in += AES_BLOCK_SIZE;
75 out += AES_BLOCK_SIZE;
Richard Henderson838e4632020-08-28 10:05:17 -070076 len -= AES_BLOCK_SIZE;
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000077 }
78}
79
Richard Henderson8ee47cd2020-08-28 10:05:18 -070080static void do_aes_decrypt_ecb(const void *vctx,
81 size_t len,
82 uint8_t *out,
83 const uint8_t *in)
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000084{
Richard Henderson8ee47cd2020-08-28 10:05:18 -070085 const QCryptoCipherBuiltinAESContext *ctx = vctx;
Richard Henderson838e4632020-08-28 10:05:17 -070086
87 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000088 while (len) {
Richard Henderson8ee47cd2020-08-28 10:05:18 -070089 AES_decrypt(in, out, &ctx->dec);
90 in += AES_BLOCK_SIZE;
91 out += AES_BLOCK_SIZE;
Richard Henderson838e4632020-08-28 10:05:17 -070092 len -= AES_BLOCK_SIZE;
Daniel P. Berrangee3ba0b62016-02-11 14:05:21 +000093 }
94}
95
Richard Hendersonef186f42020-08-28 10:05:20 -070096static void do_aes_encrypt_cbc(const AES_KEY *key,
97 size_t len,
98 uint8_t *out,
99 const uint8_t *in,
100 uint8_t *ivec)
Richard Hendersona2d76b62020-08-28 10:05:19 -0700101{
Richard Hendersonef186f42020-08-28 10:05:20 -0700102 uint8_t tmp[AES_BLOCK_SIZE];
103 size_t n;
Richard Hendersona2d76b62020-08-28 10:05:19 -0700104
Richard Hendersonef186f42020-08-28 10:05:20 -0700105 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
106 while (len) {
107 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
108 tmp[n] = in[n] ^ ivec[n];
Richard Hendersona2d76b62020-08-28 10:05:19 -0700109 }
Richard Hendersonef186f42020-08-28 10:05:20 -0700110 AES_encrypt(tmp, out, key);
111 memcpy(ivec, out, AES_BLOCK_SIZE);
112 len -= AES_BLOCK_SIZE;
113 in += AES_BLOCK_SIZE;
114 out += AES_BLOCK_SIZE;
Richard Hendersona2d76b62020-08-28 10:05:19 -0700115 }
116}
117
Richard Hendersonef186f42020-08-28 10:05:20 -0700118static void do_aes_decrypt_cbc(const AES_KEY *key,
119 size_t len,
120 uint8_t *out,
121 const uint8_t *in,
122 uint8_t *ivec)
123{
124 uint8_t tmp[AES_BLOCK_SIZE];
125 size_t n;
126
127 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
128 while (len) {
129 memcpy(tmp, in, AES_BLOCK_SIZE);
130 AES_decrypt(in, out, key);
131 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
132 out[n] ^= ivec[n];
133 }
134 memcpy(ivec, tmp, AES_BLOCK_SIZE);
135 len -= AES_BLOCK_SIZE;
136 in += AES_BLOCK_SIZE;
137 out += AES_BLOCK_SIZE;
138 }
139}
Richard Hendersona2d76b62020-08-28 10:05:19 -0700140
Richard Hendersona3db31b2020-08-28 10:05:21 -0700141static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
142 const void *in, void *out,
143 size_t len, Error **errp)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100144{
Richard Hendersona3db31b2020-08-28 10:05:21 -0700145 QCryptoCipherBuiltinAES *ctx
146 = container_of(cipher, QCryptoCipherBuiltinAES, base);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100147
Richard Hendersona3db31b2020-08-28 10:05:21 -0700148 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
149 return -1;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100150 }
Richard Hendersona3db31b2020-08-28 10:05:21 -0700151 do_aes_encrypt_ecb(&ctx->key, len, out, in);
152 return 0;
153}
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100154
Richard Hendersona3db31b2020-08-28 10:05:21 -0700155static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
156 const void *in, void *out,
157 size_t len, Error **errp)
158{
159 QCryptoCipherBuiltinAES *ctx
160 = container_of(cipher, QCryptoCipherBuiltinAES, base);
161
162 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
163 return -1;
164 }
165 do_aes_decrypt_ecb(&ctx->key, len, out, in);
166 return 0;
167}
168
169static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
170 const void *in, void *out,
171 size_t len, Error **errp)
172{
173 QCryptoCipherBuiltinAES *ctx
174 = container_of(cipher, QCryptoCipherBuiltinAES, base);
175
176 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
177 return -1;
178 }
179 do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
180 return 0;
181}
182
183static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
184 const void *in, void *out,
185 size_t len, Error **errp)
186{
187 QCryptoCipherBuiltinAES *ctx
188 = container_of(cipher, QCryptoCipherBuiltinAES, base);
189
190 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
191 return -1;
192 }
193 do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
194 return 0;
195}
196
197static int qcrypto_cipher_aes_encrypt_xts(QCryptoCipher *cipher,
198 const void *in, void *out,
199 size_t len, Error **errp)
200{
201 QCryptoCipherBuiltinAES *ctx
202 = container_of(cipher, QCryptoCipherBuiltinAES, base);
203
204 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
205 return -1;
206 }
207 xts_encrypt(&ctx->key, &ctx->key_tweak,
208 do_aes_encrypt_ecb, do_aes_decrypt_ecb,
209 ctx->iv, len, out, in);
210 return 0;
211}
212
213static int qcrypto_cipher_aes_decrypt_xts(QCryptoCipher *cipher,
214 const void *in, void *out,
215 size_t len, Error **errp)
216{
217 QCryptoCipherBuiltinAES *ctx
218 = container_of(cipher, QCryptoCipherBuiltinAES, base);
219
220 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
221 return -1;
222 }
223 xts_decrypt(&ctx->key, &ctx->key_tweak,
224 do_aes_encrypt_ecb, do_aes_decrypt_ecb,
225 ctx->iv, len, out, in);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100226 return 0;
227}
228
229
Richard Hendersona3db31b2020-08-28 10:05:21 -0700230static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
231 size_t niv, Error **errp)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100232{
Richard Hendersona3db31b2020-08-28 10:05:21 -0700233 QCryptoCipherBuiltinAES *ctx
234 = container_of(cipher, QCryptoCipherBuiltinAES, base);
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700235
Daniel P. Berrangeeb2a7702015-10-16 13:23:13 +0100236 if (niv != AES_BLOCK_SIZE) {
237 error_setg(errp, "IV must be %d bytes not %zu",
238 AES_BLOCK_SIZE, niv);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100239 return -1;
240 }
241
Richard Hendersona3db31b2020-08-28 10:05:21 -0700242 memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100243 return 0;
244}
245
Richard Hendersona3db31b2020-08-28 10:05:21 -0700246static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = {
247 .cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb,
248 .cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb,
249 .cipher_setiv = qcrypto_cipher_no_setiv,
250 .cipher_free = qcrypto_cipher_ctx_free,
251};
252
253static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
254 .cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc,
255 .cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc,
256 .cipher_setiv = qcrypto_cipher_aes_setiv,
257 .cipher_free = qcrypto_cipher_ctx_free,
258};
259
260static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_xts = {
261 .cipher_encrypt = qcrypto_cipher_aes_encrypt_xts,
262 .cipher_decrypt = qcrypto_cipher_aes_decrypt_xts,
263 .cipher_setiv = qcrypto_cipher_aes_setiv,
264 .cipher_free = qcrypto_cipher_ctx_free,
265};
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100266
267
Richard Hendersona3db31b2020-08-28 10:05:21 -0700268typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
269struct QCryptoCipherBuiltinDESRFB {
270 QCryptoCipher base;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100271
Richard Hendersona3db31b2020-08-28 10:05:21 -0700272 /* C.f. alg_key_len[QCRYPTO_CIPHER_ALG_DES_RFB] */
273 uint8_t key[8];
274};
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100275
276static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
Richard Hendersona3db31b2020-08-28 10:05:21 -0700277 const void *in, void *out,
278 size_t len, Error **errp)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100279{
Richard Hendersona3db31b2020-08-28 10:05:21 -0700280 QCryptoCipherBuiltinDESRFB *ctx
281 = container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100282 size_t i;
283
Richard Hendersona3db31b2020-08-28 10:05:21 -0700284 if (!qcrypto_length_check(len, 8, errp)) {
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100285 return -1;
286 }
287
Richard Hendersona3db31b2020-08-28 10:05:21 -0700288 deskey(ctx->key, EN0);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100289
290 for (i = 0; i < len; i += 8) {
291 des((void *)in + i, out + i);
292 }
293
294 return 0;
295}
296
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100297static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
Richard Hendersona3db31b2020-08-28 10:05:21 -0700298 const void *in, void *out,
299 size_t len, Error **errp)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100300{
Richard Hendersona3db31b2020-08-28 10:05:21 -0700301 QCryptoCipherBuiltinDESRFB *ctx
302 = container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100303 size_t i;
304
Richard Hendersona3db31b2020-08-28 10:05:21 -0700305 if (!qcrypto_length_check(len, 8, errp)) {
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100306 return -1;
307 }
308
Richard Hendersona3db31b2020-08-28 10:05:21 -0700309 deskey(ctx->key, DE1);
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100310
311 for (i = 0; i < len; i += 8) {
312 des((void *)in + i, out + i);
313 }
314
315 return 0;
316}
317
Richard Hendersona3db31b2020-08-28 10:05:21 -0700318static const struct QCryptoCipherDriver qcrypto_cipher_des_rfb_driver = {
319 .cipher_encrypt = qcrypto_cipher_encrypt_des_rfb,
320 .cipher_decrypt = qcrypto_cipher_decrypt_des_rfb,
321 .cipher_setiv = qcrypto_cipher_no_setiv,
322 .cipher_free = qcrypto_cipher_ctx_free,
323};
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100324
Gongleif8448362016-09-26 17:23:21 +0800325bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
326 QCryptoCipherMode mode)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100327{
328 switch (alg) {
329 case QCRYPTO_CIPHER_ALG_DES_RFB:
Richard Hendersona3db31b2020-08-28 10:05:21 -0700330 return mode == QCRYPTO_CIPHER_MODE_ECB;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100331 case QCRYPTO_CIPHER_ALG_AES_128:
332 case QCRYPTO_CIPHER_ALG_AES_192:
333 case QCRYPTO_CIPHER_ALG_AES_256:
Richard Hendersona3db31b2020-08-28 10:05:21 -0700334 switch (mode) {
335 case QCRYPTO_CIPHER_MODE_ECB:
336 case QCRYPTO_CIPHER_MODE_CBC:
337 case QCRYPTO_CIPHER_MODE_XTS:
338 return true;
339 default:
340 return false;
341 }
Gongleif8448362016-09-26 17:23:21 +0800342 break;
343 default:
344 return false;
345 }
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100346}
347
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700348static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
349 QCryptoCipherMode mode,
350 const uint8_t *key,
351 size_t nkey,
352 Error **errp)
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100353{
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000354 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
Longpeng(Mike)d962c622017-07-14 14:03:57 -0400355 return NULL;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100356 }
357
Longpeng(Mike)d962c622017-07-14 14:03:57 -0400358 switch (alg) {
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100359 case QCRYPTO_CIPHER_ALG_DES_RFB:
Richard Hendersona3db31b2020-08-28 10:05:21 -0700360 if (mode == QCRYPTO_CIPHER_MODE_ECB) {
361 QCryptoCipherBuiltinDESRFB *ctx;
362
363 ctx = g_new0(QCryptoCipherBuiltinDESRFB, 1);
364 ctx->base.driver = &qcrypto_cipher_des_rfb_driver;
365 memcpy(ctx->key, key, sizeof(ctx->key));
366
367 return &ctx->base;
368 }
369 goto bad_mode;
370
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100371 case QCRYPTO_CIPHER_ALG_AES_128:
372 case QCRYPTO_CIPHER_ALG_AES_192:
373 case QCRYPTO_CIPHER_ALG_AES_256:
Richard Hendersona3db31b2020-08-28 10:05:21 -0700374 {
375 QCryptoCipherBuiltinAES *ctx;
376 const QCryptoCipherDriver *drv;
377
378 switch (mode) {
379 case QCRYPTO_CIPHER_MODE_ECB:
380 drv = &qcrypto_cipher_aes_driver_ecb;
381 break;
382 case QCRYPTO_CIPHER_MODE_CBC:
383 drv = &qcrypto_cipher_aes_driver_cbc;
384 break;
385 case QCRYPTO_CIPHER_MODE_XTS:
386 drv = &qcrypto_cipher_aes_driver_xts;
387 break;
388 default:
389 goto bad_mode;
390 }
391
392 ctx = g_new0(QCryptoCipherBuiltinAES, 1);
393 ctx->base.driver = drv;
394
395 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
396 nkey /= 2;
397 if (AES_set_encrypt_key(key + nkey, nkey * 8,
398 &ctx->key_tweak.enc)) {
399 error_setg(errp, "Failed to set encryption key");
400 goto error;
401 }
402 if (AES_set_decrypt_key(key + nkey, nkey * 8,
403 &ctx->key_tweak.dec)) {
404 error_setg(errp, "Failed to set decryption key");
405 goto error;
406 }
407 }
408 if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
409 error_setg(errp, "Failed to set encryption key");
410 goto error;
411 }
412 if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
413 error_setg(errp, "Failed to set decryption key");
414 goto error;
415 }
416
417 return &ctx->base;
418
419 error:
420 g_free(ctx);
421 return NULL;
422 }
423
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100424 default:
425 error_setg(errp,
Daniel P. Berrange90d6f602016-09-05 18:02:05 +0100426 "Unsupported cipher algorithm %s",
Markus Armbruster977c7362017-08-24 10:46:08 +0200427 QCryptoCipherAlgorithm_str(alg));
Longpeng(Mike)d962c622017-07-14 14:03:57 -0400428 return NULL;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100429 }
Richard Hendersona3db31b2020-08-28 10:05:21 -0700430
431 bad_mode:
432 error_setg(errp, "Unsupported cipher mode %s",
433 QCryptoCipherMode_str(mode));
434 return NULL;
Daniel P. Berrangeca38a4c2015-07-01 18:10:32 +0100435}