1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "crypto/xts.h"
23#include "cipherpriv.h"
24
25#include <gcrypt.h>
26
27
28bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
29 QCryptoCipherMode mode)
30{
31 switch (alg) {
32 case QCRYPTO_CIPHER_ALG_DES_RFB:
33 case QCRYPTO_CIPHER_ALG_3DES:
34 case QCRYPTO_CIPHER_ALG_AES_128:
35 case QCRYPTO_CIPHER_ALG_AES_192:
36 case QCRYPTO_CIPHER_ALG_AES_256:
37 case QCRYPTO_CIPHER_ALG_CAST5_128:
38 case QCRYPTO_CIPHER_ALG_SERPENT_128:
39 case QCRYPTO_CIPHER_ALG_SERPENT_192:
40 case QCRYPTO_CIPHER_ALG_SERPENT_256:
41 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
42 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
43 break;
44 default:
45 return false;
46 }
47
48 switch (mode) {
49 case QCRYPTO_CIPHER_MODE_ECB:
50 case QCRYPTO_CIPHER_MODE_CBC:
51 case QCRYPTO_CIPHER_MODE_XTS:
52 case QCRYPTO_CIPHER_MODE_CTR:
53 return true;
54 default:
55 return false;
56 }
57}
58
59typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
60struct QCryptoCipherGcrypt {
61 gcry_cipher_hd_t handle;
62 gcry_cipher_hd_t tweakhandle;
63 size_t blocksize;
64
65 uint8_t *iv;
66};
67
68static void
69qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
70 QCryptoCipherMode mode)
71{
72 if (!ctx) {
73 return;
74 }
75
76 gcry_cipher_close(ctx->handle);
77 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
78 gcry_cipher_close(ctx->tweakhandle);
79 }
80 g_free(ctx->iv);
81 g_free(ctx);
82}
83
84
85static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
86 QCryptoCipherMode mode,
87 const uint8_t *key,
88 size_t nkey,
89 Error **errp)
90{
91 QCryptoCipherGcrypt *ctx;
92 gcry_error_t err;
93 int gcryalg, gcrymode;
94
95 switch (mode) {
96 case QCRYPTO_CIPHER_MODE_ECB:
97 case QCRYPTO_CIPHER_MODE_XTS:
98 gcrymode = GCRY_CIPHER_MODE_ECB;
99 break;
100 case QCRYPTO_CIPHER_MODE_CBC:
101 gcrymode = GCRY_CIPHER_MODE_CBC;
102 break;
103 case QCRYPTO_CIPHER_MODE_CTR:
104 gcrymode = GCRY_CIPHER_MODE_CTR;
105 break;
106 default:
107 error_setg(errp, "Unsupported cipher mode %s",
108 QCryptoCipherMode_lookup[mode]);
109 return NULL;
110 }
111
112 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
113 return NULL;
114 }
115
116 switch (alg) {
117 case QCRYPTO_CIPHER_ALG_DES_RFB:
118 gcryalg = GCRY_CIPHER_DES;
119 break;
120
121 case QCRYPTO_CIPHER_ALG_3DES:
122 gcryalg = GCRY_CIPHER_3DES;
123 break;
124
125 case QCRYPTO_CIPHER_ALG_AES_128:
126 gcryalg = GCRY_CIPHER_AES128;
127 break;
128
129 case QCRYPTO_CIPHER_ALG_AES_192:
130 gcryalg = GCRY_CIPHER_AES192;
131 break;
132
133 case QCRYPTO_CIPHER_ALG_AES_256:
134 gcryalg = GCRY_CIPHER_AES256;
135 break;
136
137 case QCRYPTO_CIPHER_ALG_CAST5_128:
138 gcryalg = GCRY_CIPHER_CAST5;
139 break;
140
141 case QCRYPTO_CIPHER_ALG_SERPENT_128:
142 gcryalg = GCRY_CIPHER_SERPENT128;
143 break;
144
145 case QCRYPTO_CIPHER_ALG_SERPENT_192:
146 gcryalg = GCRY_CIPHER_SERPENT192;
147 break;
148
149 case QCRYPTO_CIPHER_ALG_SERPENT_256:
150 gcryalg = GCRY_CIPHER_SERPENT256;
151 break;
152
153 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
154 gcryalg = GCRY_CIPHER_TWOFISH128;
155 break;
156
157 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
158 gcryalg = GCRY_CIPHER_TWOFISH;
159 break;
160
161 default:
162 error_setg(errp, "Unsupported cipher algorithm %s",
163 QCryptoCipherAlgorithm_lookup[alg]);
164 return NULL;
165 }
166
167 ctx = g_new0(QCryptoCipherGcrypt, 1);
168
169 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
170 if (err != 0) {
171 error_setg(errp, "Cannot initialize cipher: %s",
172 gcry_strerror(err));
173 goto error;
174 }
175 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
176 err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
177 if (err != 0) {
178 error_setg(errp, "Cannot initialize cipher: %s",
179 gcry_strerror(err));
180 goto error;
181 }
182 }
183
184 if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
185
186
187
188
189 uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
190 err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
191 g_free(rfbkey);
192 ctx->blocksize = 8;
193 } else {
194 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
195 nkey /= 2;
196 err = gcry_cipher_setkey(ctx->handle, key, nkey);
197 if (err != 0) {
198 error_setg(errp, "Cannot set key: %s",
199 gcry_strerror(err));
200 goto error;
201 }
202 err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
203 } else {
204 err = gcry_cipher_setkey(ctx->handle, key, nkey);
205 }
206 if (err != 0) {
207 error_setg(errp, "Cannot set key: %s",
208 gcry_strerror(err));
209 goto error;
210 }
211 switch (alg) {
212 case QCRYPTO_CIPHER_ALG_AES_128:
213 case QCRYPTO_CIPHER_ALG_AES_192:
214 case QCRYPTO_CIPHER_ALG_AES_256:
215 case QCRYPTO_CIPHER_ALG_SERPENT_128:
216 case QCRYPTO_CIPHER_ALG_SERPENT_192:
217 case QCRYPTO_CIPHER_ALG_SERPENT_256:
218 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
219 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
220 ctx->blocksize = 16;
221 break;
222 case QCRYPTO_CIPHER_ALG_3DES:
223 case QCRYPTO_CIPHER_ALG_CAST5_128:
224 ctx->blocksize = 8;
225 break;
226 default:
227 g_assert_not_reached();
228 }
229 }
230
231 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
232 if (ctx->blocksize != XTS_BLOCK_SIZE) {
233 error_setg(errp,
234 "Cipher block size %zu must equal XTS block size %d",
235 ctx->blocksize, XTS_BLOCK_SIZE);
236 goto error;
237 }
238 ctx->iv = g_new0(uint8_t, ctx->blocksize);
239 }
240
241 return ctx;
242
243 error:
244 qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
245 return NULL;
246}
247
248
249static void
250qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
251{
252 qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode);
253}
254
255
256static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
257 size_t length,
258 uint8_t *dst,
259 const uint8_t *src)
260{
261 gcry_error_t err;
262 err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
263 g_assert(err == 0);
264}
265
266static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
267 size_t length,
268 uint8_t *dst,
269 const uint8_t *src)
270{
271 gcry_error_t err;
272 err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
273 g_assert(err == 0);
274}
275
276static int
277qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
278 const void *in,
279 void *out,
280 size_t len,
281 Error **errp)
282{
283 QCryptoCipherGcrypt *ctx = cipher->opaque;
284 gcry_error_t err;
285
286 if (len % ctx->blocksize) {
287 error_setg(errp, "Length %zu must be a multiple of block size %zu",
288 len, ctx->blocksize);
289 return -1;
290 }
291
292 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
293 xts_encrypt(ctx->handle, ctx->tweakhandle,
294 qcrypto_gcrypt_xts_encrypt,
295 qcrypto_gcrypt_xts_decrypt,
296 ctx->iv, len, out, in);
297 } else {
298 err = gcry_cipher_encrypt(ctx->handle,
299 out, len,
300 in, len);
301 if (err != 0) {
302 error_setg(errp, "Cannot encrypt data: %s",
303 gcry_strerror(err));
304 return -1;
305 }
306 }
307
308 return 0;
309}
310
311
312static int
313qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
314 const void *in,
315 void *out,
316 size_t len,
317 Error **errp)
318{
319 QCryptoCipherGcrypt *ctx = cipher->opaque;
320 gcry_error_t err;
321
322 if (len % ctx->blocksize) {
323 error_setg(errp, "Length %zu must be a multiple of block size %zu",
324 len, ctx->blocksize);
325 return -1;
326 }
327
328 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
329 xts_decrypt(ctx->handle, ctx->tweakhandle,
330 qcrypto_gcrypt_xts_encrypt,
331 qcrypto_gcrypt_xts_decrypt,
332 ctx->iv, len, out, in);
333 } else {
334 err = gcry_cipher_decrypt(ctx->handle,
335 out, len,
336 in, len);
337 if (err != 0) {
338 error_setg(errp, "Cannot decrypt data: %s",
339 gcry_strerror(err));
340 return -1;
341 }
342 }
343
344 return 0;
345}
346
347static int
348qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
349 const uint8_t *iv, size_t niv,
350 Error **errp)
351{
352 QCryptoCipherGcrypt *ctx = cipher->opaque;
353 gcry_error_t err;
354
355 if (niv != ctx->blocksize) {
356 error_setg(errp, "Expected IV size %zu not %zu",
357 ctx->blocksize, niv);
358 return -1;
359 }
360
361 if (ctx->iv) {
362 memcpy(ctx->iv, iv, niv);
363 } else {
364 if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
365 err = gcry_cipher_setctr(ctx->handle, iv, niv);
366 if (err != 0) {
367 error_setg(errp, "Cannot set Counter: %s",
368 gcry_strerror(err));
369 return -1;
370 }
371 } else {
372 gcry_cipher_reset(ctx->handle);
373 err = gcry_cipher_setiv(ctx->handle, iv, niv);
374 if (err != 0) {
375 error_setg(errp, "Cannot set IV: %s",
376 gcry_strerror(err));
377 return -1;
378 }
379 }
380 }
381
382 return 0;
383}
384
385
386static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = {
387 .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt,
388 .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt,
389 .cipher_setiv = qcrypto_gcrypt_cipher_setiv,
390 .cipher_free = qcrypto_gcrypt_cipher_ctx_free,
391};
392