blob: a6a0117717f5bc1061e91612981ee26eaa8a1d3b [file] [log] [blame]
Daniel P. Berrange62893b62015-07-01 18:10:33 +01001/*
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
Thomas Huthb7cbb872019-02-13 16:54:59 +01009 * version 2.1 of the License, or (at your option) any later version.
Daniel P. Berrange62893b62015-07-01 18:10:33 +010010 *
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
Gongleif8448362016-09-26 17:23:21 +080023bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
24 QCryptoCipherMode mode)
Daniel P. Berrange62893b62015-07-01 18:10:33 +010025{
26 switch (alg) {
Daniel P. Berrangé83bee4b2021-06-29 14:25:32 +010027 case QCRYPTO_CIPHER_ALG_DES:
Longpeng(Mike)ffb7bf42016-12-08 10:33:28 +080028 case QCRYPTO_CIPHER_ALG_3DES:
Daniel P. Berrange62893b62015-07-01 18:10:33 +010029 case QCRYPTO_CIPHER_ALG_AES_128:
30 case QCRYPTO_CIPHER_ALG_AES_192:
31 case QCRYPTO_CIPHER_ALG_AES_256:
Daniel P. Berrange084a85e2016-02-10 17:07:42 +000032 case QCRYPTO_CIPHER_ALG_CAST5_128:
Daniel P. Berrange94318522016-02-10 17:07:42 +000033 case QCRYPTO_CIPHER_ALG_SERPENT_128:
34 case QCRYPTO_CIPHER_ALG_SERPENT_192:
35 case QCRYPTO_CIPHER_ALG_SERPENT_256:
Daniel P. Berrange50f67532016-02-10 17:07:42 +000036 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
37 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
Gongleif8448362016-09-26 17:23:21 +080038 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:
Daniel P. Berrange62893b62015-07-01 18:10:33 +010048 return true;
49 default:
50 return false;
51 }
52}
53
Richard Henderson1b010d92020-08-28 10:05:23 -070054typedef struct QCryptoCipherGcrypt {
Richard Henderson3eedf5c2020-08-28 10:05:14 -070055 QCryptoCipher base;
Daniel P. Berrange3a661f12015-10-16 16:35:06 +010056 gcry_cipher_hd_t handle;
57 size_t blocksize;
Richard Henderson1b010d92020-08-28 10:05:23 -070058} QCryptoCipherGcrypt;
Daniel P. Berrange62893b62015-07-01 18:10:33 +010059
Richard Henderson1b010d92020-08-28 10:05:23 -070060
61static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
Longpeng(Mike)cc5eff02017-07-14 14:03:54 -040062{
Richard Henderson1b010d92020-08-28 10:05:23 -070063 QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
Longpeng(Mike)cc5eff02017-07-14 14:03:54 -040064
65 gcry_cipher_close(ctx->handle);
Longpeng(Mike)cc5eff02017-07-14 14:03:54 -040066 g_free(ctx);
67}
68
Richard Henderson1b010d92020-08-28 10:05:23 -070069static 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
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700173static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
174 QCryptoCipherMode mode,
175 const uint8_t *key,
176 size_t nkey,
177 Error **errp)
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100178{
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100179 QCryptoCipherGcrypt *ctx;
Richard Henderson1b010d92020-08-28 10:05:23 -0700180 const QCryptoCipherDriver *drv;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100181 gcry_error_t err;
182 int gcryalg, gcrymode;
183
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000184 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100185 return NULL;
186 }
187
188 switch (alg) {
Daniel P. Berrangé83bee4b2021-06-29 14:25:32 +0100189 case QCRYPTO_CIPHER_ALG_DES:
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100190 gcryalg = GCRY_CIPHER_DES;
191 break;
Longpeng(Mike)ffb7bf42016-12-08 10:33:28 +0800192 case QCRYPTO_CIPHER_ALG_3DES:
193 gcryalg = GCRY_CIPHER_3DES;
194 break;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100195 case QCRYPTO_CIPHER_ALG_AES_128:
196 gcryalg = GCRY_CIPHER_AES128;
197 break;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100198 case QCRYPTO_CIPHER_ALG_AES_192:
199 gcryalg = GCRY_CIPHER_AES192;
200 break;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100201 case QCRYPTO_CIPHER_ALG_AES_256:
202 gcryalg = GCRY_CIPHER_AES256;
203 break;
Daniel P. Berrange084a85e2016-02-10 17:07:42 +0000204 case QCRYPTO_CIPHER_ALG_CAST5_128:
205 gcryalg = GCRY_CIPHER_CAST5;
206 break;
Daniel P. Berrange94318522016-02-10 17:07:42 +0000207 case QCRYPTO_CIPHER_ALG_SERPENT_128:
208 gcryalg = GCRY_CIPHER_SERPENT128;
209 break;
Daniel P. Berrange94318522016-02-10 17:07:42 +0000210 case QCRYPTO_CIPHER_ALG_SERPENT_192:
211 gcryalg = GCRY_CIPHER_SERPENT192;
212 break;
Daniel P. Berrange94318522016-02-10 17:07:42 +0000213 case QCRYPTO_CIPHER_ALG_SERPENT_256:
214 gcryalg = GCRY_CIPHER_SERPENT256;
215 break;
Daniel P. Berrange50f67532016-02-10 17:07:42 +0000216 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
217 gcryalg = GCRY_CIPHER_TWOFISH128;
218 break;
Daniel P. Berrange50f67532016-02-10 17:07:42 +0000219 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
220 gcryalg = GCRY_CIPHER_TWOFISH;
221 break;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100222 default:
Daniel P. Berrange90d6f602016-09-05 18:02:05 +0100223 error_setg(errp, "Unsupported cipher algorithm %s",
Markus Armbruster977c7362017-08-24 10:46:08 +0200224 QCryptoCipherAlgorithm_str(alg));
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100225 return NULL;
226 }
227
Richard Henderson1b010d92020-08-28 10:05:23 -0700228 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:
Richard Henderson1b010d92020-08-28 10:05:23 -0700234 gcrymode = GCRY_CIPHER_MODE_XTS;
Richard Henderson1b010d92020-08-28 10:05:23 -0700235 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
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100249 ctx = g_new0(QCryptoCipherGcrypt, 1);
Richard Henderson1b010d92020-08-28 10:05:23 -0700250 ctx->base.driver = drv;
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100251
252 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100253 if (err != 0) {
254 error_setg(errp, "Cannot initialize cipher: %s",
255 gcry_strerror(err));
256 goto error;
257 }
Richard Henderson1b010d92020-08-28 10:05:23 -0700258 ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
259
Daniel P. Berrangé83bee4b2021-06-29 14:25:32 +0100260 err = gcry_cipher_setkey(ctx->handle, key, nkey);
Richard Henderson1b010d92020-08-28 10:05:23 -0700261 if (err != 0) {
262 error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
263 goto error;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100264 }
265
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700266 return &ctx->base;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100267
268 error:
Richard Henderson1b010d92020-08-28 10:05:23 -0700269 gcry_cipher_close(ctx->handle);
270 g_free(ctx);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100271 return NULL;
272}