]> git.proxmox.com Git - mirror_qemu.git/blob - crypto/cipher-builtin.c
crypto: refactor code for dealing with AES cipher
[mirror_qemu.git] / crypto / cipher-builtin.c
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 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 "qemu/osdep.h"
22 #include "crypto/aes.h"
23 #include "crypto/desrfb.h"
24
25 typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
26 struct QCryptoCipherBuiltinAESContext {
27 AES_KEY enc;
28 AES_KEY dec;
29 };
30 typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
31 struct QCryptoCipherBuiltinAES {
32 QCryptoCipherBuiltinAESContext key;
33 uint8_t iv[AES_BLOCK_SIZE];
34 };
35 typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
36 struct QCryptoCipherBuiltinDESRFB {
37 uint8_t *key;
38 size_t nkey;
39 };
40
41 typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
42 struct QCryptoCipherBuiltin {
43 union {
44 QCryptoCipherBuiltinAES aes;
45 QCryptoCipherBuiltinDESRFB desrfb;
46 } state;
47 size_t blocksize;
48 void (*free)(QCryptoCipher *cipher);
49 int (*setiv)(QCryptoCipher *cipher,
50 const uint8_t *iv, size_t niv,
51 Error **errp);
52 int (*encrypt)(QCryptoCipher *cipher,
53 const void *in,
54 void *out,
55 size_t len,
56 Error **errp);
57 int (*decrypt)(QCryptoCipher *cipher,
58 const void *in,
59 void *out,
60 size_t len,
61 Error **errp);
62 };
63
64
65 static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
66 {
67 QCryptoCipherBuiltin *ctxt = cipher->opaque;
68
69 g_free(ctxt);
70 cipher->opaque = NULL;
71 }
72
73
74 static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
75 const void *in,
76 void *out,
77 size_t len)
78 {
79 const uint8_t *inptr = in;
80 uint8_t *outptr = out;
81 while (len) {
82 if (len > AES_BLOCK_SIZE) {
83 AES_encrypt(inptr, outptr, key);
84 inptr += AES_BLOCK_SIZE;
85 outptr += AES_BLOCK_SIZE;
86 len -= AES_BLOCK_SIZE;
87 } else {
88 uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
89 memcpy(tmp1, inptr, len);
90 /* Fill with 0 to avoid valgrind uninitialized reads */
91 memset(tmp1 + len, 0, sizeof(tmp1) - len);
92 AES_encrypt(tmp1, tmp2, key);
93 memcpy(outptr, tmp2, len);
94 len = 0;
95 }
96 }
97 }
98
99
100 static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
101 const void *in,
102 void *out,
103 size_t len)
104 {
105 const uint8_t *inptr = in;
106 uint8_t *outptr = out;
107 while (len) {
108 if (len > AES_BLOCK_SIZE) {
109 AES_decrypt(inptr, outptr, key);
110 inptr += AES_BLOCK_SIZE;
111 outptr += AES_BLOCK_SIZE;
112 len -= AES_BLOCK_SIZE;
113 } else {
114 uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
115 memcpy(tmp1, inptr, len);
116 /* Fill with 0 to avoid valgrind uninitialized reads */
117 memset(tmp1 + len, 0, sizeof(tmp1) - len);
118 AES_decrypt(tmp1, tmp2, key);
119 memcpy(outptr, tmp2, len);
120 len = 0;
121 }
122 }
123 }
124
125
126 static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
127 const void *in,
128 void *out,
129 size_t len,
130 Error **errp)
131 {
132 QCryptoCipherBuiltin *ctxt = cipher->opaque;
133
134 switch (cipher->mode) {
135 case QCRYPTO_CIPHER_MODE_ECB:
136 qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
137 in, out, len);
138 break;
139 case QCRYPTO_CIPHER_MODE_CBC:
140 AES_cbc_encrypt(in, out, len,
141 &ctxt->state.aes.key.enc,
142 ctxt->state.aes.iv, 1);
143 break;
144 default:
145 g_assert_not_reached();
146 }
147
148 return 0;
149 }
150
151
152 static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
153 const void *in,
154 void *out,
155 size_t len,
156 Error **errp)
157 {
158 QCryptoCipherBuiltin *ctxt = cipher->opaque;
159
160 switch (cipher->mode) {
161 case QCRYPTO_CIPHER_MODE_ECB:
162 qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
163 in, out, len);
164 break;
165 case QCRYPTO_CIPHER_MODE_CBC:
166 AES_cbc_encrypt(in, out, len,
167 &ctxt->state.aes.key.dec,
168 ctxt->state.aes.iv, 0);
169 break;
170 default:
171 g_assert_not_reached();
172 }
173
174 return 0;
175 }
176
177 static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher,
178 const uint8_t *iv, size_t niv,
179 Error **errp)
180 {
181 QCryptoCipherBuiltin *ctxt = cipher->opaque;
182 if (niv != AES_BLOCK_SIZE) {
183 error_setg(errp, "IV must be %d bytes not %zu",
184 AES_BLOCK_SIZE, niv);
185 return -1;
186 }
187
188 memcpy(ctxt->state.aes.iv, iv, AES_BLOCK_SIZE);
189
190 return 0;
191 }
192
193
194
195
196 static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
197 const uint8_t *key, size_t nkey,
198 Error **errp)
199 {
200 QCryptoCipherBuiltin *ctxt;
201
202 if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
203 cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
204 error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
205 return -1;
206 }
207
208 ctxt = g_new0(QCryptoCipherBuiltin, 1);
209
210 if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
211 error_setg(errp, "Failed to set encryption key");
212 goto error;
213 }
214
215 if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
216 error_setg(errp, "Failed to set decryption key");
217 goto error;
218 }
219
220 ctxt->blocksize = AES_BLOCK_SIZE;
221 ctxt->free = qcrypto_cipher_free_aes;
222 ctxt->setiv = qcrypto_cipher_setiv_aes;
223 ctxt->encrypt = qcrypto_cipher_encrypt_aes;
224 ctxt->decrypt = qcrypto_cipher_decrypt_aes;
225
226 cipher->opaque = ctxt;
227
228 return 0;
229
230 error:
231 g_free(ctxt);
232 return -1;
233 }
234
235
236 static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher)
237 {
238 QCryptoCipherBuiltin *ctxt = cipher->opaque;
239
240 g_free(ctxt->state.desrfb.key);
241 g_free(ctxt);
242 cipher->opaque = NULL;
243 }
244
245
246 static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
247 const void *in,
248 void *out,
249 size_t len,
250 Error **errp)
251 {
252 QCryptoCipherBuiltin *ctxt = cipher->opaque;
253 size_t i;
254
255 if (len % 8) {
256 error_setg(errp, "Buffer size must be multiple of 8 not %zu",
257 len);
258 return -1;
259 }
260
261 deskey(ctxt->state.desrfb.key, EN0);
262
263 for (i = 0; i < len; i += 8) {
264 des((void *)in + i, out + i);
265 }
266
267 return 0;
268 }
269
270
271 static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
272 const void *in,
273 void *out,
274 size_t len,
275 Error **errp)
276 {
277 QCryptoCipherBuiltin *ctxt = cipher->opaque;
278 size_t i;
279
280 if (len % 8) {
281 error_setg(errp, "Buffer size must be multiple of 8 not %zu",
282 len);
283 return -1;
284 }
285
286 deskey(ctxt->state.desrfb.key, DE1);
287
288 for (i = 0; i < len; i += 8) {
289 des((void *)in + i, out + i);
290 }
291
292 return 0;
293 }
294
295
296 static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher,
297 const uint8_t *iv, size_t niv,
298 Error **errp)
299 {
300 error_setg(errp, "Setting IV is not supported");
301 return -1;
302 }
303
304
305 static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
306 const uint8_t *key, size_t nkey,
307 Error **errp)
308 {
309 QCryptoCipherBuiltin *ctxt;
310
311 if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
312 error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
313 return -1;
314 }
315
316 ctxt = g_new0(QCryptoCipherBuiltin, 1);
317
318 ctxt->state.desrfb.key = g_new0(uint8_t, nkey);
319 memcpy(ctxt->state.desrfb.key, key, nkey);
320 ctxt->state.desrfb.nkey = nkey;
321
322 ctxt->blocksize = 8;
323 ctxt->free = qcrypto_cipher_free_des_rfb;
324 ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
325 ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
326 ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb;
327
328 cipher->opaque = ctxt;
329
330 return 0;
331 }
332
333
334 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
335 {
336 switch (alg) {
337 case QCRYPTO_CIPHER_ALG_DES_RFB:
338 case QCRYPTO_CIPHER_ALG_AES_128:
339 case QCRYPTO_CIPHER_ALG_AES_192:
340 case QCRYPTO_CIPHER_ALG_AES_256:
341 return true;
342 default:
343 return false;
344 }
345 }
346
347
348 QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
349 QCryptoCipherMode mode,
350 const uint8_t *key, size_t nkey,
351 Error **errp)
352 {
353 QCryptoCipher *cipher;
354
355 cipher = g_new0(QCryptoCipher, 1);
356 cipher->alg = alg;
357 cipher->mode = mode;
358
359 if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
360 goto error;
361 }
362
363 switch (cipher->alg) {
364 case QCRYPTO_CIPHER_ALG_DES_RFB:
365 if (qcrypto_cipher_init_des_rfb(cipher, key, nkey, errp) < 0) {
366 goto error;
367 }
368 break;
369 case QCRYPTO_CIPHER_ALG_AES_128:
370 case QCRYPTO_CIPHER_ALG_AES_192:
371 case QCRYPTO_CIPHER_ALG_AES_256:
372 if (qcrypto_cipher_init_aes(cipher, key, nkey, errp) < 0) {
373 goto error;
374 }
375 break;
376 default:
377 error_setg(errp,
378 "Unsupported cipher algorithm %d", cipher->alg);
379 goto error;
380 }
381
382 return cipher;
383
384 error:
385 g_free(cipher);
386 return NULL;
387 }
388
389 void qcrypto_cipher_free(QCryptoCipher *cipher)
390 {
391 QCryptoCipherBuiltin *ctxt;
392
393 if (!cipher) {
394 return;
395 }
396
397 ctxt = cipher->opaque;
398 ctxt->free(cipher);
399 g_free(cipher);
400 }
401
402
403 int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
404 const void *in,
405 void *out,
406 size_t len,
407 Error **errp)
408 {
409 QCryptoCipherBuiltin *ctxt = cipher->opaque;
410
411 if (len % ctxt->blocksize) {
412 error_setg(errp, "Length %zu must be a multiple of block size %zu",
413 len, ctxt->blocksize);
414 return -1;
415 }
416
417 return ctxt->encrypt(cipher, in, out, len, errp);
418 }
419
420
421 int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
422 const void *in,
423 void *out,
424 size_t len,
425 Error **errp)
426 {
427 QCryptoCipherBuiltin *ctxt = cipher->opaque;
428
429 if (len % ctxt->blocksize) {
430 error_setg(errp, "Length %zu must be a multiple of block size %zu",
431 len, ctxt->blocksize);
432 return -1;
433 }
434
435 return ctxt->decrypt(cipher, in, out, len, errp);
436 }
437
438
439 int qcrypto_cipher_setiv(QCryptoCipher *cipher,
440 const uint8_t *iv, size_t niv,
441 Error **errp)
442 {
443 QCryptoCipherBuiltin *ctxt = cipher->opaque;
444
445 return ctxt->setiv(cipher, iv, niv, errp);
446 }