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