blob: 10d75da75da2cedc536ed1055e3f5106a111444b [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
9 * version 2 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
Peter Maydell42f7a442016-01-26 18:16:55 +000021#include "qemu/osdep.h"
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000022#include "crypto/xts.h"
Longpeng(Mike)75c80072017-07-14 14:03:58 -040023#include "cipherpriv.h"
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000024
Daniel P. Berrange62893b62015-07-01 18:10:33 +010025#include <gcrypt.h>
26
27
Gongleif8448362016-09-26 17:23:21 +080028bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
29 QCryptoCipherMode mode)
Daniel P. Berrange62893b62015-07-01 18:10:33 +010030{
31 switch (alg) {
32 case QCRYPTO_CIPHER_ALG_DES_RFB:
Longpeng(Mike)ffb7bf42016-12-08 10:33:28 +080033 case QCRYPTO_CIPHER_ALG_3DES:
Daniel P. Berrange62893b62015-07-01 18:10:33 +010034 case QCRYPTO_CIPHER_ALG_AES_128:
35 case QCRYPTO_CIPHER_ALG_AES_192:
36 case QCRYPTO_CIPHER_ALG_AES_256:
Daniel P. Berrange084a85e2016-02-10 17:07:42 +000037 case QCRYPTO_CIPHER_ALG_CAST5_128:
Daniel P. Berrange94318522016-02-10 17:07:42 +000038 case QCRYPTO_CIPHER_ALG_SERPENT_128:
39 case QCRYPTO_CIPHER_ALG_SERPENT_192:
40 case QCRYPTO_CIPHER_ALG_SERPENT_256:
Daniel P. Berrange50f67532016-02-10 17:07:42 +000041 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
42 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
Gongleif8448362016-09-26 17:23:21 +080043 break;
44 default:
45 return false;
46 }
47
48 switch (mode) {
49 case QCRYPTO_CIPHER_MODE_ECB:
50 case QCRYPTO_CIPHER_MODE_CBC:
51 case QCRYPTO_CIPHER_MODE_XTS:
52 case QCRYPTO_CIPHER_MODE_CTR:
Daniel P. Berrange62893b62015-07-01 18:10:33 +010053 return true;
54 default:
55 return false;
56 }
57}
58
Daniel P. Berrange3a661f12015-10-16 16:35:06 +010059typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
60struct QCryptoCipherGcrypt {
61 gcry_cipher_hd_t handle;
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000062 gcry_cipher_hd_t tweakhandle;
Daniel P. Berrange3a661f12015-10-16 16:35:06 +010063 size_t blocksize;
Gonglei3c282922016-09-26 17:23:22 +080064 /* Initialization vector or Counter */
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000065 uint8_t *iv;
Daniel P. Berrange3a661f12015-10-16 16:35:06 +010066};
Daniel P. Berrange62893b62015-07-01 18:10:33 +010067
Longpeng(Mike)75c80072017-07-14 14:03:58 -040068static void
69qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
70 QCryptoCipherMode mode)
Longpeng(Mike)cc5eff02017-07-14 14:03:54 -040071{
72 if (!ctx) {
73 return;
74 }
75
76 gcry_cipher_close(ctx->handle);
77 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
78 gcry_cipher_close(ctx->tweakhandle);
79 }
80 g_free(ctx->iv);
81 g_free(ctx);
82}
83
84
Longpeng(Mike)468fb272017-07-14 14:03:55 -040085static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
86 QCryptoCipherMode mode,
87 const uint8_t *key,
88 size_t nkey,
89 Error **errp)
Daniel P. Berrange62893b62015-07-01 18:10:33 +010090{
Daniel P. Berrange3a661f12015-10-16 16:35:06 +010091 QCryptoCipherGcrypt *ctx;
Daniel P. Berrange62893b62015-07-01 18:10:33 +010092 gcry_error_t err;
93 int gcryalg, gcrymode;
94
95 switch (mode) {
96 case QCRYPTO_CIPHER_MODE_ECB:
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +000097 case QCRYPTO_CIPHER_MODE_XTS:
Daniel P. Berrange62893b62015-07-01 18:10:33 +010098 gcrymode = GCRY_CIPHER_MODE_ECB;
99 break;
100 case QCRYPTO_CIPHER_MODE_CBC:
101 gcrymode = GCRY_CIPHER_MODE_CBC;
102 break;
Gonglei3c282922016-09-26 17:23:22 +0800103 case QCRYPTO_CIPHER_MODE_CTR:
104 gcrymode = GCRY_CIPHER_MODE_CTR;
105 break;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100106 default:
Daniel P. Berrange90d6f602016-09-05 18:02:05 +0100107 error_setg(errp, "Unsupported cipher mode %s",
Markus Armbruster977c7362017-08-24 10:46:08 +0200108 QCryptoCipherMode_str(mode));
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100109 return NULL;
110 }
111
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000112 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100113 return NULL;
114 }
115
116 switch (alg) {
117 case QCRYPTO_CIPHER_ALG_DES_RFB:
118 gcryalg = GCRY_CIPHER_DES;
119 break;
120
Longpeng(Mike)ffb7bf42016-12-08 10:33:28 +0800121 case QCRYPTO_CIPHER_ALG_3DES:
122 gcryalg = GCRY_CIPHER_3DES;
123 break;
124
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100125 case QCRYPTO_CIPHER_ALG_AES_128:
126 gcryalg = GCRY_CIPHER_AES128;
127 break;
128
129 case QCRYPTO_CIPHER_ALG_AES_192:
130 gcryalg = GCRY_CIPHER_AES192;
131 break;
132
133 case QCRYPTO_CIPHER_ALG_AES_256:
134 gcryalg = GCRY_CIPHER_AES256;
135 break;
136
Daniel P. Berrange084a85e2016-02-10 17:07:42 +0000137 case QCRYPTO_CIPHER_ALG_CAST5_128:
138 gcryalg = GCRY_CIPHER_CAST5;
139 break;
140
Daniel P. Berrange94318522016-02-10 17:07:42 +0000141 case QCRYPTO_CIPHER_ALG_SERPENT_128:
142 gcryalg = GCRY_CIPHER_SERPENT128;
143 break;
144
145 case QCRYPTO_CIPHER_ALG_SERPENT_192:
146 gcryalg = GCRY_CIPHER_SERPENT192;
147 break;
148
149 case QCRYPTO_CIPHER_ALG_SERPENT_256:
150 gcryalg = GCRY_CIPHER_SERPENT256;
151 break;
152
Daniel P. Berrange50f67532016-02-10 17:07:42 +0000153 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
154 gcryalg = GCRY_CIPHER_TWOFISH128;
155 break;
156
157 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
158 gcryalg = GCRY_CIPHER_TWOFISH;
159 break;
160
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100161 default:
Daniel P. Berrange90d6f602016-09-05 18:02:05 +0100162 error_setg(errp, "Unsupported cipher algorithm %s",
Markus Armbruster977c7362017-08-24 10:46:08 +0200163 QCryptoCipherAlgorithm_str(alg));
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100164 return NULL;
165 }
166
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100167 ctx = g_new0(QCryptoCipherGcrypt, 1);
168
169 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100170 if (err != 0) {
171 error_setg(errp, "Cannot initialize cipher: %s",
172 gcry_strerror(err));
173 goto error;
174 }
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400175 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000176 err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
177 if (err != 0) {
178 error_setg(errp, "Cannot initialize cipher: %s",
179 gcry_strerror(err));
180 goto error;
181 }
182 }
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100183
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400184 if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100185 /* We're using standard DES cipher from gcrypt, so we need
186 * to munge the key so that the results are the same as the
187 * bizarre RFB variant of DES :-)
188 */
189 uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100190 err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100191 g_free(rfbkey);
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100192 ctx->blocksize = 8;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100193 } else {
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400194 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000195 nkey /= 2;
196 err = gcry_cipher_setkey(ctx->handle, key, nkey);
197 if (err != 0) {
198 error_setg(errp, "Cannot set key: %s",
199 gcry_strerror(err));
200 goto error;
201 }
202 err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
203 } else {
204 err = gcry_cipher_setkey(ctx->handle, key, nkey);
205 }
206 if (err != 0) {
207 error_setg(errp, "Cannot set key: %s",
208 gcry_strerror(err));
209 goto error;
210 }
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400211 switch (alg) {
Daniel P. Berrange084a85e2016-02-10 17:07:42 +0000212 case QCRYPTO_CIPHER_ALG_AES_128:
213 case QCRYPTO_CIPHER_ALG_AES_192:
214 case QCRYPTO_CIPHER_ALG_AES_256:
Daniel P. Berrange94318522016-02-10 17:07:42 +0000215 case QCRYPTO_CIPHER_ALG_SERPENT_128:
216 case QCRYPTO_CIPHER_ALG_SERPENT_192:
217 case QCRYPTO_CIPHER_ALG_SERPENT_256:
Daniel P. Berrange50f67532016-02-10 17:07:42 +0000218 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
219 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
Daniel P. Berrange084a85e2016-02-10 17:07:42 +0000220 ctx->blocksize = 16;
221 break;
Longpeng(Mike)ffb7bf42016-12-08 10:33:28 +0800222 case QCRYPTO_CIPHER_ALG_3DES:
Daniel P. Berrange084a85e2016-02-10 17:07:42 +0000223 case QCRYPTO_CIPHER_ALG_CAST5_128:
224 ctx->blocksize = 8;
225 break;
226 default:
227 g_assert_not_reached();
228 }
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100229 }
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000230
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400231 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
Daniel P. Berrangea5d2f442016-08-24 16:28:15 +0100232 if (ctx->blocksize != XTS_BLOCK_SIZE) {
233 error_setg(errp,
234 "Cipher block size %zu must equal XTS block size %d",
235 ctx->blocksize, XTS_BLOCK_SIZE);
236 goto error;
237 }
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000238 ctx->iv = g_new0(uint8_t, ctx->blocksize);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100239 }
240
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400241 return ctx;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100242
243 error:
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400244 qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100245 return NULL;
246}
247
248
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400249static void
250qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100251{
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400252 qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode);
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100253}
254
255
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000256static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
257 size_t length,
258 uint8_t *dst,
259 const uint8_t *src)
260{
261 gcry_error_t err;
262 err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
263 g_assert(err == 0);
264}
265
266static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
267 size_t length,
268 uint8_t *dst,
269 const uint8_t *src)
270{
271 gcry_error_t err;
272 err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
273 g_assert(err == 0);
274}
275
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400276static int
277qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
278 const void *in,
279 void *out,
280 size_t len,
281 Error **errp)
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100282{
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100283 QCryptoCipherGcrypt *ctx = cipher->opaque;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100284 gcry_error_t err;
285
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100286 if (len % ctx->blocksize) {
287 error_setg(errp, "Length %zu must be a multiple of block size %zu",
288 len, ctx->blocksize);
289 return -1;
290 }
291
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000292 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
293 xts_encrypt(ctx->handle, ctx->tweakhandle,
294 qcrypto_gcrypt_xts_encrypt,
295 qcrypto_gcrypt_xts_decrypt,
296 ctx->iv, len, out, in);
297 } else {
298 err = gcry_cipher_encrypt(ctx->handle,
299 out, len,
300 in, len);
301 if (err != 0) {
302 error_setg(errp, "Cannot encrypt data: %s",
303 gcry_strerror(err));
304 return -1;
305 }
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100306 }
307
308 return 0;
309}
310
311
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400312static int
313qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
314 const void *in,
315 void *out,
316 size_t len,
317 Error **errp)
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100318{
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100319 QCryptoCipherGcrypt *ctx = cipher->opaque;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100320 gcry_error_t err;
321
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100322 if (len % ctx->blocksize) {
323 error_setg(errp, "Length %zu must be a multiple of block size %zu",
324 len, ctx->blocksize);
325 return -1;
326 }
327
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000328 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
329 xts_decrypt(ctx->handle, ctx->tweakhandle,
330 qcrypto_gcrypt_xts_encrypt,
331 qcrypto_gcrypt_xts_decrypt,
332 ctx->iv, len, out, in);
333 } else {
334 err = gcry_cipher_decrypt(ctx->handle,
335 out, len,
336 in, len);
337 if (err != 0) {
338 error_setg(errp, "Cannot decrypt data: %s",
339 gcry_strerror(err));
340 return -1;
341 }
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100342 }
343
344 return 0;
345}
346
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400347static int
348qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
349 const uint8_t *iv, size_t niv,
350 Error **errp)
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100351{
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100352 QCryptoCipherGcrypt *ctx = cipher->opaque;
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100353 gcry_error_t err;
354
Daniel P. Berrange3a661f12015-10-16 16:35:06 +0100355 if (niv != ctx->blocksize) {
356 error_setg(errp, "Expected IV size %zu not %zu",
357 ctx->blocksize, niv);
358 return -1;
359 }
360
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000361 if (ctx->iv) {
362 memcpy(ctx->iv, iv, niv);
363 } else {
Gonglei3c282922016-09-26 17:23:22 +0800364 if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
365 err = gcry_cipher_setctr(ctx->handle, iv, niv);
366 if (err != 0) {
367 error_setg(errp, "Cannot set Counter: %s",
368 gcry_strerror(err));
369 return -1;
370 }
371 } else {
372 gcry_cipher_reset(ctx->handle);
373 err = gcry_cipher_setiv(ctx->handle, iv, niv);
374 if (err != 0) {
375 error_setg(errp, "Cannot set IV: %s",
376 gcry_strerror(err));
377 return -1;
378 }
Daniel P. Berrangeeaec9032016-02-11 14:05:21 +0000379 }
Daniel P. Berrange62893b62015-07-01 18:10:33 +0100380 }
381
382 return 0;
383}
Longpeng(Mike)468fb272017-07-14 14:03:55 -0400384
385
Longpeng(Mike)75c80072017-07-14 14:03:58 -0400386static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = {
387 .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt,
388 .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt,
389 .cipher_setiv = qcrypto_gcrypt_cipher_setiv,
390 .cipher_free = qcrypto_gcrypt_cipher_ctx_free,
391};