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