]> Git Repo - qemu.git/blob - crypto/cipher-gcrypt.c
target/arm: fix code comments error
[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 };
This page took 0.04544 seconds and 4 git commands to generate.