xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision 6d92bdf44375f9819539927b7f234ba89ce9365e)
1*6d92bdf4SRichard Henderson/*
2*6d92bdf4SRichard Henderson * QEMU Crypto cipher libgcrypt algorithms
3*6d92bdf4SRichard Henderson *
4*6d92bdf4SRichard Henderson * Copyright (c) 2015 Red Hat, Inc.
5*6d92bdf4SRichard Henderson *
6*6d92bdf4SRichard Henderson * This library is free software; you can redistribute it and/or
7*6d92bdf4SRichard Henderson * modify it under the terms of the GNU Lesser General Public
8*6d92bdf4SRichard Henderson * License as published by the Free Software Foundation; either
9*6d92bdf4SRichard Henderson * version 2.1 of the License, or (at your option) any later version.
10*6d92bdf4SRichard Henderson *
11*6d92bdf4SRichard Henderson * This library is distributed in the hope that it will be useful,
12*6d92bdf4SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*6d92bdf4SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*6d92bdf4SRichard Henderson * Lesser General Public License for more details.
15*6d92bdf4SRichard Henderson *
16*6d92bdf4SRichard Henderson * You should have received a copy of the GNU Lesser General Public
17*6d92bdf4SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*6d92bdf4SRichard Henderson *
19*6d92bdf4SRichard Henderson */
20*6d92bdf4SRichard Henderson
21*6d92bdf4SRichard Henderson#include "qemu/osdep.h"
22*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
23*6d92bdf4SRichard Henderson#include "crypto/xts.h"
24*6d92bdf4SRichard Henderson#endif
25*6d92bdf4SRichard Henderson#include "cipherpriv.h"
26*6d92bdf4SRichard Henderson
27*6d92bdf4SRichard Henderson#include <gcrypt.h>
28*6d92bdf4SRichard Henderson
29*6d92bdf4SRichard Henderson
30*6d92bdf4SRichard Hendersonbool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
31*6d92bdf4SRichard Henderson                             QCryptoCipherMode mode)
32*6d92bdf4SRichard Henderson{
33*6d92bdf4SRichard Henderson    switch (alg) {
34*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_DES_RFB:
35*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_3DES:
36*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_128:
37*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_192:
38*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_256:
39*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_CAST5_128:
40*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_128:
41*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_192:
42*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_256:
43*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
44*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
45*6d92bdf4SRichard Henderson        break;
46*6d92bdf4SRichard Henderson    default:
47*6d92bdf4SRichard Henderson        return false;
48*6d92bdf4SRichard Henderson    }
49*6d92bdf4SRichard Henderson
50*6d92bdf4SRichard Henderson    switch (mode) {
51*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
52*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
53*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
54*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
55*6d92bdf4SRichard Henderson        return true;
56*6d92bdf4SRichard Henderson    default:
57*6d92bdf4SRichard Henderson        return false;
58*6d92bdf4SRichard Henderson    }
59*6d92bdf4SRichard Henderson}
60*6d92bdf4SRichard Henderson
61*6d92bdf4SRichard Hendersontypedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
62*6d92bdf4SRichard Hendersonstruct QCryptoCipherGcrypt {
63*6d92bdf4SRichard Henderson    gcry_cipher_hd_t handle;
64*6d92bdf4SRichard Henderson    size_t blocksize;
65*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
66*6d92bdf4SRichard Henderson    gcry_cipher_hd_t tweakhandle;
67*6d92bdf4SRichard Henderson    /* Initialization vector or Counter */
68*6d92bdf4SRichard Henderson    uint8_t *iv;
69*6d92bdf4SRichard Henderson#endif
70*6d92bdf4SRichard Henderson};
71*6d92bdf4SRichard Henderson
72*6d92bdf4SRichard Hendersonstatic void
73*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
74*6d92bdf4SRichard Henderson                               QCryptoCipherMode mode)
75*6d92bdf4SRichard Henderson{
76*6d92bdf4SRichard Henderson    if (!ctx) {
77*6d92bdf4SRichard Henderson        return;
78*6d92bdf4SRichard Henderson    }
79*6d92bdf4SRichard Henderson
80*6d92bdf4SRichard Henderson    gcry_cipher_close(ctx->handle);
81*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
82*6d92bdf4SRichard Henderson    if (mode == QCRYPTO_CIPHER_MODE_XTS) {
83*6d92bdf4SRichard Henderson        gcry_cipher_close(ctx->tweakhandle);
84*6d92bdf4SRichard Henderson    }
85*6d92bdf4SRichard Henderson    g_free(ctx->iv);
86*6d92bdf4SRichard Henderson#endif
87*6d92bdf4SRichard Henderson    g_free(ctx);
88*6d92bdf4SRichard Henderson}
89*6d92bdf4SRichard Henderson
90*6d92bdf4SRichard Henderson
91*6d92bdf4SRichard Hendersonstatic QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
92*6d92bdf4SRichard Henderson                                                   QCryptoCipherMode mode,
93*6d92bdf4SRichard Henderson                                                   const uint8_t *key,
94*6d92bdf4SRichard Henderson                                                   size_t nkey,
95*6d92bdf4SRichard Henderson                                                   Error **errp)
96*6d92bdf4SRichard Henderson{
97*6d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx;
98*6d92bdf4SRichard Henderson    gcry_error_t err;
99*6d92bdf4SRichard Henderson    int gcryalg, gcrymode;
100*6d92bdf4SRichard Henderson
101*6d92bdf4SRichard Henderson    switch (mode) {
102*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
103*6d92bdf4SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_ECB;
104*6d92bdf4SRichard Henderson        break;
105*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
106*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
107*6d92bdf4SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_ECB;
108*6d92bdf4SRichard Henderson#else
109*6d92bdf4SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_XTS;
110*6d92bdf4SRichard Henderson#endif
111*6d92bdf4SRichard Henderson        break;
112*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
113*6d92bdf4SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_CBC;
114*6d92bdf4SRichard Henderson        break;
115*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
116*6d92bdf4SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_CTR;
117*6d92bdf4SRichard Henderson        break;
118*6d92bdf4SRichard Henderson    default:
119*6d92bdf4SRichard Henderson        error_setg(errp, "Unsupported cipher mode %s",
120*6d92bdf4SRichard Henderson                   QCryptoCipherMode_str(mode));
121*6d92bdf4SRichard Henderson        return NULL;
122*6d92bdf4SRichard Henderson    }
123*6d92bdf4SRichard Henderson
124*6d92bdf4SRichard Henderson    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
125*6d92bdf4SRichard Henderson        return NULL;
126*6d92bdf4SRichard Henderson    }
127*6d92bdf4SRichard Henderson
128*6d92bdf4SRichard Henderson    switch (alg) {
129*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_DES_RFB:
130*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_DES;
131*6d92bdf4SRichard Henderson        break;
132*6d92bdf4SRichard Henderson
133*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_3DES:
134*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_3DES;
135*6d92bdf4SRichard Henderson        break;
136*6d92bdf4SRichard Henderson
137*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_128:
138*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES128;
139*6d92bdf4SRichard Henderson        break;
140*6d92bdf4SRichard Henderson
141*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_192:
142*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES192;
143*6d92bdf4SRichard Henderson        break;
144*6d92bdf4SRichard Henderson
145*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_256:
146*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES256;
147*6d92bdf4SRichard Henderson        break;
148*6d92bdf4SRichard Henderson
149*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_CAST5_128:
150*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_CAST5;
151*6d92bdf4SRichard Henderson        break;
152*6d92bdf4SRichard Henderson
153*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_128:
154*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT128;
155*6d92bdf4SRichard Henderson        break;
156*6d92bdf4SRichard Henderson
157*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_192:
158*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT192;
159*6d92bdf4SRichard Henderson        break;
160*6d92bdf4SRichard Henderson
161*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_256:
162*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT256;
163*6d92bdf4SRichard Henderson        break;
164*6d92bdf4SRichard Henderson
165*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
166*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_TWOFISH128;
167*6d92bdf4SRichard Henderson        break;
168*6d92bdf4SRichard Henderson
169*6d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
170*6d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_TWOFISH;
171*6d92bdf4SRichard Henderson        break;
172*6d92bdf4SRichard Henderson
173*6d92bdf4SRichard Henderson    default:
174*6d92bdf4SRichard Henderson        error_setg(errp, "Unsupported cipher algorithm %s",
175*6d92bdf4SRichard Henderson                   QCryptoCipherAlgorithm_str(alg));
176*6d92bdf4SRichard Henderson        return NULL;
177*6d92bdf4SRichard Henderson    }
178*6d92bdf4SRichard Henderson
179*6d92bdf4SRichard Henderson    ctx = g_new0(QCryptoCipherGcrypt, 1);
180*6d92bdf4SRichard Henderson
181*6d92bdf4SRichard Henderson    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
182*6d92bdf4SRichard Henderson    if (err != 0) {
183*6d92bdf4SRichard Henderson        error_setg(errp, "Cannot initialize cipher: %s",
184*6d92bdf4SRichard Henderson                   gcry_strerror(err));
185*6d92bdf4SRichard Henderson        goto error;
186*6d92bdf4SRichard Henderson    }
187*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
188*6d92bdf4SRichard Henderson    if (mode == QCRYPTO_CIPHER_MODE_XTS) {
189*6d92bdf4SRichard Henderson        err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
190*6d92bdf4SRichard Henderson        if (err != 0) {
191*6d92bdf4SRichard Henderson            error_setg(errp, "Cannot initialize cipher: %s",
192*6d92bdf4SRichard Henderson                       gcry_strerror(err));
193*6d92bdf4SRichard Henderson            goto error;
194*6d92bdf4SRichard Henderson        }
195*6d92bdf4SRichard Henderson    }
196*6d92bdf4SRichard Henderson#endif
197*6d92bdf4SRichard Henderson
198*6d92bdf4SRichard Henderson    if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
199*6d92bdf4SRichard Henderson        /* We're using standard DES cipher from gcrypt, so we need
200*6d92bdf4SRichard Henderson         * to munge the key so that the results are the same as the
201*6d92bdf4SRichard Henderson         * bizarre RFB variant of DES :-)
202*6d92bdf4SRichard Henderson         */
203*6d92bdf4SRichard Henderson        uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
204*6d92bdf4SRichard Henderson        err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
205*6d92bdf4SRichard Henderson        g_free(rfbkey);
206*6d92bdf4SRichard Henderson        ctx->blocksize = 8;
207*6d92bdf4SRichard Henderson    } else {
208*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
209*6d92bdf4SRichard Henderson        if (mode == QCRYPTO_CIPHER_MODE_XTS) {
210*6d92bdf4SRichard Henderson            nkey /= 2;
211*6d92bdf4SRichard Henderson            err = gcry_cipher_setkey(ctx->handle, key, nkey);
212*6d92bdf4SRichard Henderson            if (err != 0) {
213*6d92bdf4SRichard Henderson                error_setg(errp, "Cannot set key: %s",
214*6d92bdf4SRichard Henderson                           gcry_strerror(err));
215*6d92bdf4SRichard Henderson                goto error;
216*6d92bdf4SRichard Henderson            }
217*6d92bdf4SRichard Henderson            err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
218*6d92bdf4SRichard Henderson        } else {
219*6d92bdf4SRichard Henderson#endif
220*6d92bdf4SRichard Henderson            err = gcry_cipher_setkey(ctx->handle, key, nkey);
221*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
222*6d92bdf4SRichard Henderson        }
223*6d92bdf4SRichard Henderson#endif
224*6d92bdf4SRichard Henderson        if (err != 0) {
225*6d92bdf4SRichard Henderson            error_setg(errp, "Cannot set key: %s",
226*6d92bdf4SRichard Henderson                       gcry_strerror(err));
227*6d92bdf4SRichard Henderson            goto error;
228*6d92bdf4SRichard Henderson        }
229*6d92bdf4SRichard Henderson        switch (alg) {
230*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_AES_128:
231*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_AES_192:
232*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_AES_256:
233*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_SERPENT_128:
234*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_SERPENT_192:
235*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_SERPENT_256:
236*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_TWOFISH_128:
237*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_TWOFISH_256:
238*6d92bdf4SRichard Henderson            ctx->blocksize = 16;
239*6d92bdf4SRichard Henderson            break;
240*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_3DES:
241*6d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_ALG_CAST5_128:
242*6d92bdf4SRichard Henderson            ctx->blocksize = 8;
243*6d92bdf4SRichard Henderson            break;
244*6d92bdf4SRichard Henderson        default:
245*6d92bdf4SRichard Henderson            g_assert_not_reached();
246*6d92bdf4SRichard Henderson        }
247*6d92bdf4SRichard Henderson    }
248*6d92bdf4SRichard Henderson    g_assert(is_power_of_2(ctx->blocksize));
249*6d92bdf4SRichard Henderson
250*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
251*6d92bdf4SRichard Henderson    if (mode == QCRYPTO_CIPHER_MODE_XTS) {
252*6d92bdf4SRichard Henderson        if (ctx->blocksize != XTS_BLOCK_SIZE) {
253*6d92bdf4SRichard Henderson            error_setg(errp,
254*6d92bdf4SRichard Henderson                       "Cipher block size %zu must equal XTS block size %d",
255*6d92bdf4SRichard Henderson                       ctx->blocksize, XTS_BLOCK_SIZE);
256*6d92bdf4SRichard Henderson            goto error;
257*6d92bdf4SRichard Henderson        }
258*6d92bdf4SRichard Henderson        ctx->iv = g_new0(uint8_t, ctx->blocksize);
259*6d92bdf4SRichard Henderson    }
260*6d92bdf4SRichard Henderson#endif
261*6d92bdf4SRichard Henderson
262*6d92bdf4SRichard Henderson    return ctx;
263*6d92bdf4SRichard Henderson
264*6d92bdf4SRichard Henderson error:
265*6d92bdf4SRichard Henderson    qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
266*6d92bdf4SRichard Henderson    return NULL;
267*6d92bdf4SRichard Henderson}
268*6d92bdf4SRichard Henderson
269*6d92bdf4SRichard Henderson
270*6d92bdf4SRichard Hendersonstatic void
271*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
272*6d92bdf4SRichard Henderson{
273*6d92bdf4SRichard Henderson    qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode);
274*6d92bdf4SRichard Henderson}
275*6d92bdf4SRichard Henderson
276*6d92bdf4SRichard Henderson
277*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
278*6d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_encrypt(const void *ctx,
279*6d92bdf4SRichard Henderson                                       size_t length,
280*6d92bdf4SRichard Henderson                                       uint8_t *dst,
281*6d92bdf4SRichard Henderson                                       const uint8_t *src)
282*6d92bdf4SRichard Henderson{
283*6d92bdf4SRichard Henderson    gcry_error_t err;
284*6d92bdf4SRichard Henderson    err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
285*6d92bdf4SRichard Henderson    g_assert(err == 0);
286*6d92bdf4SRichard Henderson}
287*6d92bdf4SRichard Henderson
288*6d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_decrypt(const void *ctx,
289*6d92bdf4SRichard Henderson                                       size_t length,
290*6d92bdf4SRichard Henderson                                       uint8_t *dst,
291*6d92bdf4SRichard Henderson                                       const uint8_t *src)
292*6d92bdf4SRichard Henderson{
293*6d92bdf4SRichard Henderson    gcry_error_t err;
294*6d92bdf4SRichard Henderson    err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
295*6d92bdf4SRichard Henderson    g_assert(err == 0);
296*6d92bdf4SRichard Henderson}
297*6d92bdf4SRichard Henderson#endif
298*6d92bdf4SRichard Henderson
299*6d92bdf4SRichard Hendersonstatic int
300*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
301*6d92bdf4SRichard Henderson                              const void *in,
302*6d92bdf4SRichard Henderson                              void *out,
303*6d92bdf4SRichard Henderson                              size_t len,
304*6d92bdf4SRichard Henderson                              Error **errp)
305*6d92bdf4SRichard Henderson{
306*6d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx = cipher->opaque;
307*6d92bdf4SRichard Henderson    gcry_error_t err;
308*6d92bdf4SRichard Henderson
309*6d92bdf4SRichard Henderson    if (len & (ctx->blocksize - 1)) {
310*6d92bdf4SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
311*6d92bdf4SRichard Henderson                   len, ctx->blocksize);
312*6d92bdf4SRichard Henderson        return -1;
313*6d92bdf4SRichard Henderson    }
314*6d92bdf4SRichard Henderson
315*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
316*6d92bdf4SRichard Henderson    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
317*6d92bdf4SRichard Henderson        xts_encrypt(ctx->handle, ctx->tweakhandle,
318*6d92bdf4SRichard Henderson                    qcrypto_gcrypt_xts_encrypt,
319*6d92bdf4SRichard Henderson                    qcrypto_gcrypt_xts_decrypt,
320*6d92bdf4SRichard Henderson                    ctx->iv, len, out, in);
321*6d92bdf4SRichard Henderson        return 0;
322*6d92bdf4SRichard Henderson    }
323*6d92bdf4SRichard Henderson#endif
324*6d92bdf4SRichard Henderson
325*6d92bdf4SRichard Henderson    err = gcry_cipher_encrypt(ctx->handle,
326*6d92bdf4SRichard Henderson                              out, len,
327*6d92bdf4SRichard Henderson                              in, len);
328*6d92bdf4SRichard Henderson    if (err != 0) {
329*6d92bdf4SRichard Henderson        error_setg(errp, "Cannot encrypt data: %s",
330*6d92bdf4SRichard Henderson                   gcry_strerror(err));
331*6d92bdf4SRichard Henderson        return -1;
332*6d92bdf4SRichard Henderson    }
333*6d92bdf4SRichard Henderson
334*6d92bdf4SRichard Henderson    return 0;
335*6d92bdf4SRichard Henderson}
336*6d92bdf4SRichard Henderson
337*6d92bdf4SRichard Henderson
338*6d92bdf4SRichard Hendersonstatic int
339*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
340*6d92bdf4SRichard Henderson                              const void *in,
341*6d92bdf4SRichard Henderson                              void *out,
342*6d92bdf4SRichard Henderson                              size_t len,
343*6d92bdf4SRichard Henderson                              Error **errp)
344*6d92bdf4SRichard Henderson{
345*6d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx = cipher->opaque;
346*6d92bdf4SRichard Henderson    gcry_error_t err;
347*6d92bdf4SRichard Henderson
348*6d92bdf4SRichard Henderson    if (len & (ctx->blocksize - 1)) {
349*6d92bdf4SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
350*6d92bdf4SRichard Henderson                   len, ctx->blocksize);
351*6d92bdf4SRichard Henderson        return -1;
352*6d92bdf4SRichard Henderson    }
353*6d92bdf4SRichard Henderson
354*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
355*6d92bdf4SRichard Henderson    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
356*6d92bdf4SRichard Henderson        xts_decrypt(ctx->handle, ctx->tweakhandle,
357*6d92bdf4SRichard Henderson                    qcrypto_gcrypt_xts_encrypt,
358*6d92bdf4SRichard Henderson                    qcrypto_gcrypt_xts_decrypt,
359*6d92bdf4SRichard Henderson                    ctx->iv, len, out, in);
360*6d92bdf4SRichard Henderson        return 0;
361*6d92bdf4SRichard Henderson    }
362*6d92bdf4SRichard Henderson#endif
363*6d92bdf4SRichard Henderson
364*6d92bdf4SRichard Henderson    err = gcry_cipher_decrypt(ctx->handle,
365*6d92bdf4SRichard Henderson                              out, len,
366*6d92bdf4SRichard Henderson                              in, len);
367*6d92bdf4SRichard Henderson    if (err != 0) {
368*6d92bdf4SRichard Henderson        error_setg(errp, "Cannot decrypt data: %s",
369*6d92bdf4SRichard Henderson                   gcry_strerror(err));
370*6d92bdf4SRichard Henderson        return -1;
371*6d92bdf4SRichard Henderson    }
372*6d92bdf4SRichard Henderson
373*6d92bdf4SRichard Henderson    return 0;
374*6d92bdf4SRichard Henderson}
375*6d92bdf4SRichard Henderson
376*6d92bdf4SRichard Hendersonstatic int
377*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
378*6d92bdf4SRichard Henderson                            const uint8_t *iv, size_t niv,
379*6d92bdf4SRichard Henderson                            Error **errp)
380*6d92bdf4SRichard Henderson{
381*6d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx = cipher->opaque;
382*6d92bdf4SRichard Henderson    gcry_error_t err;
383*6d92bdf4SRichard Henderson
384*6d92bdf4SRichard Henderson    if (niv != ctx->blocksize) {
385*6d92bdf4SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
386*6d92bdf4SRichard Henderson                   ctx->blocksize, niv);
387*6d92bdf4SRichard Henderson        return -1;
388*6d92bdf4SRichard Henderson    }
389*6d92bdf4SRichard Henderson
390*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS
391*6d92bdf4SRichard Henderson    if (ctx->iv) {
392*6d92bdf4SRichard Henderson        memcpy(ctx->iv, iv, niv);
393*6d92bdf4SRichard Henderson        return 0;
394*6d92bdf4SRichard Henderson    }
395*6d92bdf4SRichard Henderson#endif
396*6d92bdf4SRichard Henderson
397*6d92bdf4SRichard Henderson    if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
398*6d92bdf4SRichard Henderson        err = gcry_cipher_setctr(ctx->handle, iv, niv);
399*6d92bdf4SRichard Henderson        if (err != 0) {
400*6d92bdf4SRichard Henderson            error_setg(errp, "Cannot set Counter: %s",
401*6d92bdf4SRichard Henderson                       gcry_strerror(err));
402*6d92bdf4SRichard Henderson            return -1;
403*6d92bdf4SRichard Henderson        }
404*6d92bdf4SRichard Henderson    } else {
405*6d92bdf4SRichard Henderson        gcry_cipher_reset(ctx->handle);
406*6d92bdf4SRichard Henderson        err = gcry_cipher_setiv(ctx->handle, iv, niv);
407*6d92bdf4SRichard Henderson        if (err != 0) {
408*6d92bdf4SRichard Henderson            error_setg(errp, "Cannot set IV: %s",
409*6d92bdf4SRichard Henderson                       gcry_strerror(err));
410*6d92bdf4SRichard Henderson            return -1;
411*6d92bdf4SRichard Henderson        }
412*6d92bdf4SRichard Henderson    }
413*6d92bdf4SRichard Henderson
414*6d92bdf4SRichard Henderson    return 0;
415*6d92bdf4SRichard Henderson}
416*6d92bdf4SRichard Henderson
417*6d92bdf4SRichard Henderson
418*6d92bdf4SRichard Hendersonstatic struct QCryptoCipherDriver qcrypto_cipher_lib_driver = {
419*6d92bdf4SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt,
420*6d92bdf4SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt,
421*6d92bdf4SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_cipher_setiv,
422*6d92bdf4SRichard Henderson    .cipher_free = qcrypto_gcrypt_cipher_ctx_free,
423*6d92bdf4SRichard Henderson};
424