qxl: check release info object
[qemu.git] / crypto / cipher-gcrypt.c
1 /*
2 * QEMU Crypto cipher libgcrypt 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/xts.h"
23 #include "cipherpriv.h"
24
25 #include <gcrypt.h>
26
27
28 bool 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
59 typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
60 struct QCryptoCipherGcrypt {
61 gcry_cipher_hd_t handle;
62 gcry_cipher_hd_t tweakhandle;
63 size_t blocksize;
64 /* Initialization vector or Counter */
65 uint8_t *iv;
66 };
67
68 static void
69 qcrypto_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
85 static 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_str(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_str(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 /* We're using standard DES cipher from gcrypt, so we need
186 * to munge the key so that the results are the same as the
187 * bizarre RFB variant of DES :-)
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
249 static void
250 qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
251 {
252 qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode);
253 }
254
255
256 static 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
266 static 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
276 static int
277 qcrypto_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
312 static int
313 qcrypto_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
347 static int
348 qcrypto_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
386 static 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 };