xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision 2dbb1308)
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 */
20
21#ifdef CONFIG_QEMU_PRIVATE_XTS
22#include "crypto/xts.h"
23#endif
24
25#include <gcrypt.h>
26
27bool 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
58typedef 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;
67
68
69static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
70{
71    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
72
73    gcry_cipher_close(ctx->handle);
74    g_free(ctx);
75}
76
77static int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
78                                  void *out, size_t len, Error **errp)
79{
80    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
81    gcry_error_t err;
82
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    }
88
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    }
94
95    return 0;
96}
97
98
99static int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
100                                  void *out, size_t len, Error **errp)
101{
102    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
103    gcry_error_t err;
104
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    }
110
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    }
117
118    return 0;
119}
120
121static int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
122                                const uint8_t *iv, size_t niv,
123                                Error **errp)
124{
125    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
126    gcry_error_t err;
127
128    if (niv != ctx->blocksize) {
129        error_setg(errp, "Expected IV size %zu not %zu",
130                   ctx->blocksize, niv);
131        return -1;
132    }
133
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    }
140
141    return 0;
142}
143
144static int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
145                                    const uint8_t *iv, size_t niv,
146                                    Error **errp)
147{
148    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
149    gcry_error_t err;
150
151    if (niv != ctx->blocksize) {
152        error_setg(errp, "Expected IV size %zu not %zu",
153                   ctx->blocksize, niv);
154        return -1;
155    }
156
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    }
162
163    return 0;
164}
165
166
167static 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,
172};
173
174static 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,
179};
180
181#ifdef CONFIG_QEMU_PRIVATE_XTS
182static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher)
183{
184    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
185
186    gcry_cipher_close(ctx->tweakhandle);
187    qcrypto_gcrypt_ctx_free(cipher);
188}
189
190static void qcrypto_gcrypt_xts_wrape(const void *ctx, size_t length,
191                                     uint8_t *dst, const uint8_t *src)
192{
193    gcry_error_t err;
194    err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
195    g_assert(err == 0);
196}
197
198static void qcrypto_gcrypt_xts_wrapd(const void *ctx, size_t length,
199                                     uint8_t *dst, const uint8_t *src)
200{
201    gcry_error_t err;
202    err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
203    g_assert(err == 0);
204}
205
206static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in,
207                                      void *out, size_t len, Error **errp)
208{
209    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
210
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    }
216
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;
221}
222
223static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in,
224                                      void *out, size_t len, Error **errp)
225{
226    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
227
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    }
233
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;
238}
239
240static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher,
241                                    const uint8_t *iv, size_t niv,
242                                    Error **errp)
243{
244    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
245
246    if (niv != ctx->blocksize) {
247        error_setg(errp, "Expected IV size %zu not %zu",
248                   ctx->blocksize, niv);
249        return -1;
250    }
251
252    memcpy(ctx->iv, iv, niv);
253    return 0;
254}
255
256static 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,
261};
262#endif /* CONFIG_QEMU_PRIVATE_XTS */
263
264
265static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
266                                             QCryptoCipherMode mode,
267                                             const uint8_t *key,
268                                             size_t nkey,
269                                             Error **errp)
270{
271    QCryptoCipherGcrypt *ctx;
272    const QCryptoCipherDriver *drv;
273    gcry_error_t err;
274    int gcryalg, gcrymode;
275
276    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
277        return NULL;
278    }
279
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    }
319
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    }
345
346    ctx = g_new0(QCryptoCipherGcrypt, 1);
347    ctx->base.driver = drv;
348
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);
356
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
373
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    }
399
400    return &ctx->base;
401
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;
409}
410