crypto: Move cipher->driver init to qcrypto_*_cipher_ctx_new
[qemu/ar7.git] / crypto / cipher-gcrypt.c.inc
blob7a1fbc9745608547913819d03aa6d6f6141aed1e
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  */
21 #ifdef CONFIG_QEMU_PRIVATE_XTS
22 #include "crypto/xts.h"
23 #endif
25 #include <gcrypt.h>
27 static const struct QCryptoCipherDriver qcrypto_cipher_lib_driver;
29 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
30                              QCryptoCipherMode mode)
32     switch (alg) {
33     case QCRYPTO_CIPHER_ALG_DES_RFB:
34     case QCRYPTO_CIPHER_ALG_3DES:
35     case QCRYPTO_CIPHER_ALG_AES_128:
36     case QCRYPTO_CIPHER_ALG_AES_192:
37     case QCRYPTO_CIPHER_ALG_AES_256:
38     case QCRYPTO_CIPHER_ALG_CAST5_128:
39     case QCRYPTO_CIPHER_ALG_SERPENT_128:
40     case QCRYPTO_CIPHER_ALG_SERPENT_192:
41     case QCRYPTO_CIPHER_ALG_SERPENT_256:
42     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
43     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
44         break;
45     default:
46         return false;
47     }
49     switch (mode) {
50     case QCRYPTO_CIPHER_MODE_ECB:
51     case QCRYPTO_CIPHER_MODE_CBC:
52     case QCRYPTO_CIPHER_MODE_XTS:
53     case QCRYPTO_CIPHER_MODE_CTR:
54         return true;
55     default:
56         return false;
57     }
60 typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
61 struct QCryptoCipherGcrypt {
62     QCryptoCipher base;
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
72 static void
73 qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
74                                QCryptoCipherMode mode)
76     if (!ctx) {
77         return;
78     }
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);
91 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
92                                              QCryptoCipherMode mode,
93                                              const uint8_t *key,
94                                              size_t nkey,
95                                              Error **errp)
97     QCryptoCipherGcrypt *ctx;
98     gcry_error_t err;
99     int gcryalg, gcrymode;
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     }
124     if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
125         return NULL;
126     }
128     switch (alg) {
129     case QCRYPTO_CIPHER_ALG_DES_RFB:
130         gcryalg = GCRY_CIPHER_DES;
131         break;
133     case QCRYPTO_CIPHER_ALG_3DES:
134         gcryalg = GCRY_CIPHER_3DES;
135         break;
137     case QCRYPTO_CIPHER_ALG_AES_128:
138         gcryalg = GCRY_CIPHER_AES128;
139         break;
141     case QCRYPTO_CIPHER_ALG_AES_192:
142         gcryalg = GCRY_CIPHER_AES192;
143         break;
145     case QCRYPTO_CIPHER_ALG_AES_256:
146         gcryalg = GCRY_CIPHER_AES256;
147         break;
149     case QCRYPTO_CIPHER_ALG_CAST5_128:
150         gcryalg = GCRY_CIPHER_CAST5;
151         break;
153     case QCRYPTO_CIPHER_ALG_SERPENT_128:
154         gcryalg = GCRY_CIPHER_SERPENT128;
155         break;
157     case QCRYPTO_CIPHER_ALG_SERPENT_192:
158         gcryalg = GCRY_CIPHER_SERPENT192;
159         break;
161     case QCRYPTO_CIPHER_ALG_SERPENT_256:
162         gcryalg = GCRY_CIPHER_SERPENT256;
163         break;
165     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
166         gcryalg = GCRY_CIPHER_TWOFISH128;
167         break;
169     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
170         gcryalg = GCRY_CIPHER_TWOFISH;
171         break;
173     default:
174         error_setg(errp, "Unsupported cipher algorithm %s",
175                    QCryptoCipherAlgorithm_str(alg));
176         return NULL;
177     }
179     ctx = g_new0(QCryptoCipherGcrypt, 1);
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
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     g_assert(is_power_of_2(ctx->blocksize));
250 #ifdef CONFIG_QEMU_PRIVATE_XTS
251     if (mode == QCRYPTO_CIPHER_MODE_XTS) {
252         if (ctx->blocksize != XTS_BLOCK_SIZE) {
253             error_setg(errp,
254                        "Cipher block size %zu must equal XTS block size %d",
255                        ctx->blocksize, XTS_BLOCK_SIZE);
256             goto error;
257         }
258         ctx->iv = g_new0(uint8_t, ctx->blocksize);
259     }
260 #endif
262     ctx->base.driver = &qcrypto_cipher_lib_driver;
263     return &ctx->base;
265  error:
266     qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
267     return NULL;
271 static void
272 qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
274     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
276     qcrypto_gcrypt_cipher_free_ctx(ctx, cipher->mode);
280 #ifdef CONFIG_QEMU_PRIVATE_XTS
281 static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
282                                        size_t length,
283                                        uint8_t *dst,
284                                        const uint8_t *src)
286     gcry_error_t err;
287     err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
288     g_assert(err == 0);
291 static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
292                                        size_t length,
293                                        uint8_t *dst,
294                                        const uint8_t *src)
296     gcry_error_t err;
297     err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
298     g_assert(err == 0);
300 #endif
302 static int
303 qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
304                               const void *in,
305                               void *out,
306                               size_t len,
307                               Error **errp)
309     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
310     gcry_error_t err;
312     if (len & (ctx->blocksize - 1)) {
313         error_setg(errp, "Length %zu must be a multiple of block size %zu",
314                    len, ctx->blocksize);
315         return -1;
316     }
318 #ifdef CONFIG_QEMU_PRIVATE_XTS
319     if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
320         xts_encrypt(ctx->handle, ctx->tweakhandle,
321                     qcrypto_gcrypt_xts_encrypt,
322                     qcrypto_gcrypt_xts_decrypt,
323                     ctx->iv, len, out, in);
324         return 0;
325     }
326 #endif
328     err = gcry_cipher_encrypt(ctx->handle,
329                               out, len,
330                               in, len);
331     if (err != 0) {
332         error_setg(errp, "Cannot encrypt data: %s",
333                    gcry_strerror(err));
334         return -1;
335     }
337     return 0;
341 static int
342 qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
343                               const void *in,
344                               void *out,
345                               size_t len,
346                               Error **errp)
348     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
349     gcry_error_t err;
351     if (len & (ctx->blocksize - 1)) {
352         error_setg(errp, "Length %zu must be a multiple of block size %zu",
353                    len, ctx->blocksize);
354         return -1;
355     }
357 #ifdef CONFIG_QEMU_PRIVATE_XTS
358     if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
359         xts_decrypt(ctx->handle, ctx->tweakhandle,
360                     qcrypto_gcrypt_xts_encrypt,
361                     qcrypto_gcrypt_xts_decrypt,
362                     ctx->iv, len, out, in);
363         return 0;
364     }
365 #endif
367     err = gcry_cipher_decrypt(ctx->handle,
368                               out, len,
369                               in, len);
370     if (err != 0) {
371         error_setg(errp, "Cannot decrypt data: %s",
372                    gcry_strerror(err));
373         return -1;
374     }
376     return 0;
379 static int
380 qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
381                             const uint8_t *iv, size_t niv,
382                             Error **errp)
384     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
385     gcry_error_t err;
387     if (niv != ctx->blocksize) {
388         error_setg(errp, "Expected IV size %zu not %zu",
389                    ctx->blocksize, niv);
390         return -1;
391     }
393 #ifdef CONFIG_QEMU_PRIVATE_XTS
394     if (ctx->iv) {
395         memcpy(ctx->iv, iv, niv);
396         return 0;
397     }
398 #endif
400     if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
401         err = gcry_cipher_setctr(ctx->handle, iv, niv);
402         if (err != 0) {
403             error_setg(errp, "Cannot set Counter: %s",
404                        gcry_strerror(err));
405             return -1;
406         }
407     } else {
408         gcry_cipher_reset(ctx->handle);
409         err = gcry_cipher_setiv(ctx->handle, iv, niv);
410         if (err != 0) {
411             error_setg(errp, "Cannot set IV: %s",
412                        gcry_strerror(err));
413             return -1;
414         }
415     }
417     return 0;
421 static const struct QCryptoCipherDriver qcrypto_cipher_lib_driver = {
422     .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt,
423     .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt,
424     .cipher_setiv = qcrypto_gcrypt_cipher_setiv,
425     .cipher_free = qcrypto_gcrypt_cipher_ctx_free,