xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision 6016b7b4)
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#include <gcrypt.h>
22
23bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
24                             QCryptoCipherMode mode)
25{
26    switch (alg) {
27    case QCRYPTO_CIPHER_ALG_DES:
28    case QCRYPTO_CIPHER_ALG_3DES:
29    case QCRYPTO_CIPHER_ALG_AES_128:
30    case QCRYPTO_CIPHER_ALG_AES_192:
31    case QCRYPTO_CIPHER_ALG_AES_256:
32    case QCRYPTO_CIPHER_ALG_CAST5_128:
33    case QCRYPTO_CIPHER_ALG_SERPENT_128:
34    case QCRYPTO_CIPHER_ALG_SERPENT_192:
35    case QCRYPTO_CIPHER_ALG_SERPENT_256:
36    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
37    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
38        break;
39    default:
40        return false;
41    }
42
43    switch (mode) {
44    case QCRYPTO_CIPHER_MODE_ECB:
45    case QCRYPTO_CIPHER_MODE_CBC:
46    case QCRYPTO_CIPHER_MODE_XTS:
47    case QCRYPTO_CIPHER_MODE_CTR:
48        return true;
49    default:
50        return false;
51    }
52}
53
54typedef struct QCryptoCipherGcrypt {
55    QCryptoCipher base;
56    gcry_cipher_hd_t handle;
57    size_t blocksize;
58} QCryptoCipherGcrypt;
59
60
61static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
62{
63    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
64
65    gcry_cipher_close(ctx->handle);
66    g_free(ctx);
67}
68
69static int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
70                                  void *out, size_t len, Error **errp)
71{
72    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
73    gcry_error_t err;
74
75    if (len & (ctx->blocksize - 1)) {
76        error_setg(errp, "Length %zu must be a multiple of block size %zu",
77                   len, ctx->blocksize);
78        return -1;
79    }
80
81    err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
82    if (err != 0) {
83        error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
84        return -1;
85    }
86
87    return 0;
88}
89
90
91static int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
92                                  void *out, size_t len, Error **errp)
93{
94    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
95    gcry_error_t err;
96
97    if (len & (ctx->blocksize - 1)) {
98        error_setg(errp, "Length %zu must be a multiple of block size %zu",
99                   len, ctx->blocksize);
100        return -1;
101    }
102
103    err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
104    if (err != 0) {
105        error_setg(errp, "Cannot decrypt data: %s",
106                   gcry_strerror(err));
107        return -1;
108    }
109
110    return 0;
111}
112
113static int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
114                                const uint8_t *iv, size_t niv,
115                                Error **errp)
116{
117    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
118    gcry_error_t err;
119
120    if (niv != ctx->blocksize) {
121        error_setg(errp, "Expected IV size %zu not %zu",
122                   ctx->blocksize, niv);
123        return -1;
124    }
125
126    gcry_cipher_reset(ctx->handle);
127    err = gcry_cipher_setiv(ctx->handle, iv, niv);
128    if (err != 0) {
129        error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
130        return -1;
131    }
132
133    return 0;
134}
135
136static int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
137                                    const uint8_t *iv, size_t niv,
138                                    Error **errp)
139{
140    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
141    gcry_error_t err;
142
143    if (niv != ctx->blocksize) {
144        error_setg(errp, "Expected IV size %zu not %zu",
145                   ctx->blocksize, niv);
146        return -1;
147    }
148
149    err = gcry_cipher_setctr(ctx->handle, iv, niv);
150    if (err != 0) {
151        error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
152        return -1;
153    }
154
155    return 0;
156}
157
158
159static const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
160    .cipher_encrypt = qcrypto_gcrypt_encrypt,
161    .cipher_decrypt = qcrypto_gcrypt_decrypt,
162    .cipher_setiv = qcrypto_gcrypt_setiv,
163    .cipher_free = qcrypto_gcrypt_ctx_free,
164};
165
166static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
167    .cipher_encrypt = qcrypto_gcrypt_encrypt,
168    .cipher_decrypt = qcrypto_gcrypt_decrypt,
169    .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
170    .cipher_free = qcrypto_gcrypt_ctx_free,
171};
172
173static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
174                                             QCryptoCipherMode mode,
175                                             const uint8_t *key,
176                                             size_t nkey,
177                                             Error **errp)
178{
179    QCryptoCipherGcrypt *ctx;
180    const QCryptoCipherDriver *drv;
181    gcry_error_t err;
182    int gcryalg, gcrymode;
183
184    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
185        return NULL;
186    }
187
188    switch (alg) {
189    case QCRYPTO_CIPHER_ALG_DES:
190        gcryalg = GCRY_CIPHER_DES;
191        break;
192    case QCRYPTO_CIPHER_ALG_3DES:
193        gcryalg = GCRY_CIPHER_3DES;
194        break;
195    case QCRYPTO_CIPHER_ALG_AES_128:
196        gcryalg = GCRY_CIPHER_AES128;
197        break;
198    case QCRYPTO_CIPHER_ALG_AES_192:
199        gcryalg = GCRY_CIPHER_AES192;
200        break;
201    case QCRYPTO_CIPHER_ALG_AES_256:
202        gcryalg = GCRY_CIPHER_AES256;
203        break;
204    case QCRYPTO_CIPHER_ALG_CAST5_128:
205        gcryalg = GCRY_CIPHER_CAST5;
206        break;
207    case QCRYPTO_CIPHER_ALG_SERPENT_128:
208        gcryalg = GCRY_CIPHER_SERPENT128;
209        break;
210    case QCRYPTO_CIPHER_ALG_SERPENT_192:
211        gcryalg = GCRY_CIPHER_SERPENT192;
212        break;
213    case QCRYPTO_CIPHER_ALG_SERPENT_256:
214        gcryalg = GCRY_CIPHER_SERPENT256;
215        break;
216    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
217        gcryalg = GCRY_CIPHER_TWOFISH128;
218        break;
219    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
220        gcryalg = GCRY_CIPHER_TWOFISH;
221        break;
222    default:
223        error_setg(errp, "Unsupported cipher algorithm %s",
224                   QCryptoCipherAlgorithm_str(alg));
225        return NULL;
226    }
227
228    drv = &qcrypto_gcrypt_driver;
229    switch (mode) {
230    case QCRYPTO_CIPHER_MODE_ECB:
231        gcrymode = GCRY_CIPHER_MODE_ECB;
232        break;
233    case QCRYPTO_CIPHER_MODE_XTS:
234        gcrymode = GCRY_CIPHER_MODE_XTS;
235        break;
236    case QCRYPTO_CIPHER_MODE_CBC:
237        gcrymode = GCRY_CIPHER_MODE_CBC;
238        break;
239    case QCRYPTO_CIPHER_MODE_CTR:
240        drv = &qcrypto_gcrypt_ctr_driver;
241        gcrymode = GCRY_CIPHER_MODE_CTR;
242        break;
243    default:
244        error_setg(errp, "Unsupported cipher mode %s",
245                   QCryptoCipherMode_str(mode));
246        return NULL;
247    }
248
249    ctx = g_new0(QCryptoCipherGcrypt, 1);
250    ctx->base.driver = drv;
251
252    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
253    if (err != 0) {
254        error_setg(errp, "Cannot initialize cipher: %s",
255                   gcry_strerror(err));
256        goto error;
257    }
258    ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
259
260    err = gcry_cipher_setkey(ctx->handle, key, nkey);
261    if (err != 0) {
262        error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
263        goto error;
264    }
265
266    return &ctx->base;
267
268 error:
269    gcry_cipher_close(ctx->handle);
270    g_free(ctx);
271    return NULL;
272}
273