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