hw/arm/mps2: Update old infocenter.arm.com URLs
[qemu/ar7.git] / crypto / cipher-gcrypt.c.inc
blob42d4137534f271147b4cd0cec8e556ef5904676a
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 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
28                              QCryptoCipherMode mode)
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     }
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     }
58 typedef struct QCryptoCipherGcrypt {
59     QCryptoCipher base;
60     gcry_cipher_hd_t handle;
61     size_t blocksize;
62 #ifdef CONFIG_QEMU_PRIVATE_XTS
63     gcry_cipher_hd_t tweakhandle;
64     uint8_t iv[XTS_BLOCK_SIZE];
65 #endif
66 } QCryptoCipherGcrypt;
69 static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
71     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
73     gcry_cipher_close(ctx->handle);
74     g_free(ctx);
77 static int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
78                                   void *out, size_t len, Error **errp)
80     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
81     gcry_error_t err;
83     if (len & (ctx->blocksize - 1)) {
84         error_setg(errp, "Length %zu must be a multiple of block size %zu",
85                    len, ctx->blocksize);
86         return -1;
87     }
89     err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
90     if (err != 0) {
91         error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
92         return -1;
93     }
95     return 0;
99 static int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
100                                   void *out, size_t len, Error **errp)
102     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
103     gcry_error_t err;
105     if (len & (ctx->blocksize - 1)) {
106         error_setg(errp, "Length %zu must be a multiple of block size %zu",
107                    len, ctx->blocksize);
108         return -1;
109     }
111     err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
112     if (err != 0) {
113         error_setg(errp, "Cannot decrypt data: %s",
114                    gcry_strerror(err));
115         return -1;
116     }
118     return 0;
121 static int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
122                                 const uint8_t *iv, size_t niv,
123                                 Error **errp)
125     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
126     gcry_error_t err;
128     if (niv != ctx->blocksize) {
129         error_setg(errp, "Expected IV size %zu not %zu",
130                    ctx->blocksize, niv);
131         return -1;
132     }
134     gcry_cipher_reset(ctx->handle);
135     err = gcry_cipher_setiv(ctx->handle, iv, niv);
136     if (err != 0) {
137         error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
138         return -1;
139     }
141     return 0;
144 static int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
145                                     const uint8_t *iv, size_t niv,
146                                     Error **errp)
148     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
149     gcry_error_t err;
151     if (niv != ctx->blocksize) {
152         error_setg(errp, "Expected IV size %zu not %zu",
153                    ctx->blocksize, niv);
154         return -1;
155     }
157     err = gcry_cipher_setctr(ctx->handle, iv, niv);
158     if (err != 0) {
159         error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
160         return -1;
161     }
163     return 0;
167 static const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
168     .cipher_encrypt = qcrypto_gcrypt_encrypt,
169     .cipher_decrypt = qcrypto_gcrypt_decrypt,
170     .cipher_setiv = qcrypto_gcrypt_setiv,
171     .cipher_free = qcrypto_gcrypt_ctx_free,
174 static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
175     .cipher_encrypt = qcrypto_gcrypt_encrypt,
176     .cipher_decrypt = qcrypto_gcrypt_decrypt,
177     .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
178     .cipher_free = qcrypto_gcrypt_ctx_free,
181 #ifdef CONFIG_QEMU_PRIVATE_XTS
182 static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher)
184     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
186     gcry_cipher_close(ctx->tweakhandle);
187     qcrypto_gcrypt_ctx_free(cipher);
190 static void qcrypto_gcrypt_xts_wrape(const void *ctx, size_t length,
191                                      uint8_t *dst, const uint8_t *src)
193     gcry_error_t err;
194     err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
195     g_assert(err == 0);
198 static void qcrypto_gcrypt_xts_wrapd(const void *ctx, size_t length,
199                                      uint8_t *dst, const uint8_t *src)
201     gcry_error_t err;
202     err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
203     g_assert(err == 0);
206 static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in,
207                                       void *out, size_t len, Error **errp)
209     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
211     if (len & (ctx->blocksize - 1)) {
212         error_setg(errp, "Length %zu must be a multiple of block size %zu",
213                    len, ctx->blocksize);
214         return -1;
215     }
217     xts_encrypt(ctx->handle, ctx->tweakhandle,
218                 qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
219                 ctx->iv, len, out, in);
220     return 0;
223 static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in,
224                                       void *out, size_t len, Error **errp)
226     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
228     if (len & (ctx->blocksize - 1)) {
229         error_setg(errp, "Length %zu must be a multiple of block size %zu",
230                    len, ctx->blocksize);
231         return -1;
232     }
234     xts_decrypt(ctx->handle, ctx->tweakhandle,
235                 qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
236                 ctx->iv, len, out, in);
237     return 0;
240 static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher,
241                                     const uint8_t *iv, size_t niv,
242                                     Error **errp)
244     QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
246     if (niv != ctx->blocksize) {
247         error_setg(errp, "Expected IV size %zu not %zu",
248                    ctx->blocksize, niv);
249         return -1;
250     }
252     memcpy(ctx->iv, iv, niv);
253     return 0;
256 static const struct QCryptoCipherDriver qcrypto_gcrypt_xts_driver = {
257     .cipher_encrypt = qcrypto_gcrypt_xts_encrypt,
258     .cipher_decrypt = qcrypto_gcrypt_xts_decrypt,
259     .cipher_setiv = qcrypto_gcrypt_xts_setiv,
260     .cipher_free = qcrypto_gcrypt_xts_ctx_free,
262 #endif /* CONFIG_QEMU_PRIVATE_XTS */
265 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
266                                              QCryptoCipherMode mode,
267                                              const uint8_t *key,
268                                              size_t nkey,
269                                              Error **errp)
271     QCryptoCipherGcrypt *ctx;
272     const QCryptoCipherDriver *drv;
273     gcry_error_t err;
274     int gcryalg, gcrymode;
276     if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
277         return NULL;
278     }
280     switch (alg) {
281     case QCRYPTO_CIPHER_ALG_DES_RFB:
282         gcryalg = GCRY_CIPHER_DES;
283         break;
284     case QCRYPTO_CIPHER_ALG_3DES:
285         gcryalg = GCRY_CIPHER_3DES;
286         break;
287     case QCRYPTO_CIPHER_ALG_AES_128:
288         gcryalg = GCRY_CIPHER_AES128;
289         break;
290     case QCRYPTO_CIPHER_ALG_AES_192:
291         gcryalg = GCRY_CIPHER_AES192;
292         break;
293     case QCRYPTO_CIPHER_ALG_AES_256:
294         gcryalg = GCRY_CIPHER_AES256;
295         break;
296     case QCRYPTO_CIPHER_ALG_CAST5_128:
297         gcryalg = GCRY_CIPHER_CAST5;
298         break;
299     case QCRYPTO_CIPHER_ALG_SERPENT_128:
300         gcryalg = GCRY_CIPHER_SERPENT128;
301         break;
302     case QCRYPTO_CIPHER_ALG_SERPENT_192:
303         gcryalg = GCRY_CIPHER_SERPENT192;
304         break;
305     case QCRYPTO_CIPHER_ALG_SERPENT_256:
306         gcryalg = GCRY_CIPHER_SERPENT256;
307         break;
308     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
309         gcryalg = GCRY_CIPHER_TWOFISH128;
310         break;
311     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
312         gcryalg = GCRY_CIPHER_TWOFISH;
313         break;
314     default:
315         error_setg(errp, "Unsupported cipher algorithm %s",
316                    QCryptoCipherAlgorithm_str(alg));
317         return NULL;
318     }
320     drv = &qcrypto_gcrypt_driver;
321     switch (mode) {
322     case QCRYPTO_CIPHER_MODE_ECB:
323         gcrymode = GCRY_CIPHER_MODE_ECB;
324         break;
325     case QCRYPTO_CIPHER_MODE_XTS:
326 #ifdef CONFIG_QEMU_PRIVATE_XTS
327         drv = &qcrypto_gcrypt_xts_driver;
328         gcrymode = GCRY_CIPHER_MODE_ECB;
329 #else
330         gcrymode = GCRY_CIPHER_MODE_XTS;
331 #endif
332         break;
333     case QCRYPTO_CIPHER_MODE_CBC:
334         gcrymode = GCRY_CIPHER_MODE_CBC;
335         break;
336     case QCRYPTO_CIPHER_MODE_CTR:
337         drv = &qcrypto_gcrypt_ctr_driver;
338         gcrymode = GCRY_CIPHER_MODE_CTR;
339         break;
340     default:
341         error_setg(errp, "Unsupported cipher mode %s",
342                    QCryptoCipherMode_str(mode));
343         return NULL;
344     }
346     ctx = g_new0(QCryptoCipherGcrypt, 1);
347     ctx->base.driver = drv;
349     err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
350     if (err != 0) {
351         error_setg(errp, "Cannot initialize cipher: %s",
352                    gcry_strerror(err));
353         goto error;
354     }
355     ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
357 #ifdef CONFIG_QEMU_PRIVATE_XTS
358     if (mode == QCRYPTO_CIPHER_MODE_XTS) {
359         if (ctx->blocksize != XTS_BLOCK_SIZE) {
360             error_setg(errp,
361                        "Cipher block size %zu must equal XTS block size %d",
362                        ctx->blocksize, XTS_BLOCK_SIZE);
363             goto error;
364         }
365         err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
366         if (err != 0) {
367             error_setg(errp, "Cannot initialize cipher: %s",
368                        gcry_strerror(err));
369             goto error;
370         }
371     }
372 #endif
374     if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
375         /* We're using standard DES cipher from gcrypt, so we need
376          * to munge the key so that the results are the same as the
377          * bizarre RFB variant of DES :-)
378          */
379         uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
380         err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
381         g_free(rfbkey);
382     } else {
383 #ifdef CONFIG_QEMU_PRIVATE_XTS
384         if (mode == QCRYPTO_CIPHER_MODE_XTS) {
385             nkey /= 2;
386             err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
387             if (err != 0) {
388                 error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
389                 goto error;
390             }
391         }
392 #endif
393         err = gcry_cipher_setkey(ctx->handle, key, nkey);
394     }
395     if (err != 0) {
396         error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
397         goto error;
398     }
400     return &ctx->base;
402  error:
403 #ifdef CONFIG_QEMU_PRIVATE_XTS
404     gcry_cipher_close(ctx->tweakhandle);
405 #endif
406     gcry_cipher_close(ctx->handle);
407     g_free(ctx);
408     return NULL;