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