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