2 * QEMU Crypto cipher gnutls algorithms
4 * Copyright (c) 2021 Red Hat, Inc.
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "cipherpriv.h"
24 #include <gnutls/crypto.h>
26 #if GNUTLS_VERSION_NUMBER >= 0x030608
27 #define QEMU_GNUTLS_XTS
30 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
31 QCryptoCipherMode mode)
35 case QCRYPTO_CIPHER_MODE_ECB:
36 case QCRYPTO_CIPHER_MODE_CBC:
38 case QCRYPTO_CIPHER_ALG_AES_128:
39 case QCRYPTO_CIPHER_ALG_AES_192:
40 case QCRYPTO_CIPHER_ALG_AES_256:
41 case QCRYPTO_CIPHER_ALG_DES:
42 case QCRYPTO_CIPHER_ALG_3DES:
47 #ifdef QEMU_GNUTLS_XTS
48 case QCRYPTO_CIPHER_MODE_XTS:
50 case QCRYPTO_CIPHER_ALG_AES_128:
51 case QCRYPTO_CIPHER_ALG_AES_256:
62 typedef struct QCryptoCipherGnutls QCryptoCipherGnutls;
63 struct QCryptoCipherGnutls {
65 gnutls_cipher_hd_t handle; /* XTS & CBC mode */
66 gnutls_cipher_algorithm_t galg; /* ECB mode */
67 guint8 *key; /* ECB mode */
68 size_t nkey; /* ECB mode */
74 qcrypto_gnutls_cipher_free(QCryptoCipher *cipher)
76 QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
80 gnutls_cipher_deinit(ctx->handle);
87 qcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher,
93 QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
96 if (len % ctx->blocksize) {
97 error_setg(errp, "Length %zu must be a multiple of block size %zu",
102 if (ctx->handle) { /* CBC / XTS mode */
103 err = gnutls_cipher_encrypt2(ctx->handle,
107 error_setg(errp, "Cannot encrypt data: %s",
108 gnutls_strerror(err));
111 } else { /* ECB mode very inefficiently faked with CBC */
112 g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
114 gnutls_cipher_hd_t handle;
115 gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
116 int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
118 error_setg(errp, "Cannot initialize cipher: %s",
119 gnutls_strerror(err));
123 gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
125 err = gnutls_cipher_encrypt2(handle,
127 out, ctx->blocksize);
129 gnutls_cipher_deinit(handle);
130 error_setg(errp, "Cannot encrypt data: %s",
131 gnutls_strerror(err));
134 gnutls_cipher_deinit(handle);
136 len -= ctx->blocksize;
137 in += ctx->blocksize;
138 out += ctx->blocksize;
147 qcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher,
153 QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
156 if (len % ctx->blocksize) {
157 error_setg(errp, "Length %zu must be a multiple of block size %zu",
158 len, ctx->blocksize);
162 if (ctx->handle) { /* CBC / XTS mode */
163 err = gnutls_cipher_decrypt2(ctx->handle,
168 error_setg(errp, "Cannot decrypt data: %s",
169 gnutls_strerror(err));
172 } else { /* ECB mode very inefficiently faked with CBC */
173 g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
175 gnutls_cipher_hd_t handle;
176 gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
177 int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
179 error_setg(errp, "Cannot initialize cipher: %s",
180 gnutls_strerror(err));
184 gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
186 err = gnutls_cipher_decrypt2(handle,
188 out, ctx->blocksize);
190 gnutls_cipher_deinit(handle);
191 error_setg(errp, "Cannot encrypt data: %s",
192 gnutls_strerror(err));
195 gnutls_cipher_deinit(handle);
197 len -= ctx->blocksize;
198 in += ctx->blocksize;
199 out += ctx->blocksize;
207 qcrypto_gnutls_cipher_setiv(QCryptoCipher *cipher,
208 const uint8_t *iv, size_t niv,
211 QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
213 if (niv != ctx->blocksize) {
214 error_setg(errp, "Expected IV size %zu not %zu",
215 ctx->blocksize, niv);
219 gnutls_cipher_set_iv(ctx->handle, (unsigned char *)iv, niv);
225 static struct QCryptoCipherDriver gnutls_driver = {
226 .cipher_encrypt = qcrypto_gnutls_cipher_encrypt,
227 .cipher_decrypt = qcrypto_gnutls_cipher_decrypt,
228 .cipher_setiv = qcrypto_gnutls_cipher_setiv,
229 .cipher_free = qcrypto_gnutls_cipher_free,
232 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
233 QCryptoCipherMode mode,
238 QCryptoCipherGnutls *ctx;
239 gnutls_datum_t gkey = { (unsigned char *)key, nkey };
240 gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN;
244 #ifdef QEMU_GNUTLS_XTS
245 case QCRYPTO_CIPHER_MODE_XTS:
247 case QCRYPTO_CIPHER_ALG_AES_128:
248 galg = GNUTLS_CIPHER_AES_128_XTS;
250 case QCRYPTO_CIPHER_ALG_AES_256:
251 galg = GNUTLS_CIPHER_AES_256_XTS;
259 case QCRYPTO_CIPHER_MODE_ECB:
260 case QCRYPTO_CIPHER_MODE_CBC:
262 case QCRYPTO_CIPHER_ALG_AES_128:
263 galg = GNUTLS_CIPHER_AES_128_CBC;
265 case QCRYPTO_CIPHER_ALG_AES_192:
266 galg = GNUTLS_CIPHER_AES_192_CBC;
268 case QCRYPTO_CIPHER_ALG_AES_256:
269 galg = GNUTLS_CIPHER_AES_256_CBC;
271 case QCRYPTO_CIPHER_ALG_DES:
272 galg = GNUTLS_CIPHER_DES_CBC;
274 case QCRYPTO_CIPHER_ALG_3DES:
275 galg = GNUTLS_CIPHER_3DES_CBC;
285 if (galg == GNUTLS_CIPHER_UNKNOWN) {
286 error_setg(errp, "Unsupported cipher algorithm %s with %s mode",
287 QCryptoCipherAlgorithm_str(alg),
288 QCryptoCipherMode_str(mode));
292 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
296 ctx = g_new0(QCryptoCipherGnutls, 1);
297 ctx->base.driver = &gnutls_driver;
299 if (mode == QCRYPTO_CIPHER_MODE_ECB) {
300 ctx->key = g_new0(guint8, nkey);
301 memcpy(ctx->key, key, nkey);
305 err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL);
307 error_setg(errp, "Cannot initialize cipher: %s",
308 gnutls_strerror(err));
313 if (alg == QCRYPTO_CIPHER_ALG_DES ||
314 alg == QCRYPTO_CIPHER_ALG_3DES)
320 * Our API contract for requires iv to be optional
321 * but nettle gets unhappy when called by gnutls
322 * in this case, so we just force set a default
323 * all-zeros IV, to match behaviour of other backends.
325 if (mode != QCRYPTO_CIPHER_MODE_ECB) {
326 g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
327 gnutls_cipher_set_iv(ctx->handle, iv, ctx->blocksize);
333 qcrypto_gnutls_cipher_free(&ctx->base);