13d2b61ffSDaniel P. Berrangé/* 23d2b61ffSDaniel P. Berrangé * QEMU Crypto cipher gnutls algorithms 33d2b61ffSDaniel P. Berrangé * 43d2b61ffSDaniel P. Berrangé * Copyright (c) 2021 Red Hat, Inc. 53d2b61ffSDaniel P. Berrangé * 63d2b61ffSDaniel P. Berrangé * This library is free software; you can redistribute it and/or 73d2b61ffSDaniel P. Berrangé * modify it under the terms of the GNU Lesser General Public 83d2b61ffSDaniel P. Berrangé * License as published by the Free Software Foundation; either 93d2b61ffSDaniel P. Berrangé * version 2.1 of the License, or (at your option) any later version. 103d2b61ffSDaniel P. Berrangé * 113d2b61ffSDaniel P. Berrangé * This library is distributed in the hope that it will be useful, 123d2b61ffSDaniel P. Berrangé * but WITHOUT ANY WARRANTY; without even the implied warranty of 133d2b61ffSDaniel P. Berrangé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 143d2b61ffSDaniel P. Berrangé * Lesser General Public License for more details. 153d2b61ffSDaniel P. Berrangé * 163d2b61ffSDaniel P. Berrangé * You should have received a copy of the GNU Lesser General Public 173d2b61ffSDaniel P. Berrangé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 183d2b61ffSDaniel P. Berrangé * 193d2b61ffSDaniel P. Berrangé */ 203d2b61ffSDaniel P. Berrangé 213d2b61ffSDaniel P. Berrangé#include "qemu/osdep.h" 223d2b61ffSDaniel P. Berrangé#include "cipherpriv.h" 233d2b61ffSDaniel P. Berrangé 243d2b61ffSDaniel P. Berrangé#include <gnutls/crypto.h> 253d2b61ffSDaniel P. Berrangé 263d2b61ffSDaniel P. Berrangé#if GNUTLS_VERSION_NUMBER >= 0x030608 273d2b61ffSDaniel P. Berrangé#define QEMU_GNUTLS_XTS 283d2b61ffSDaniel P. Berrangé#endif 293d2b61ffSDaniel P. Berrangé 30*a092c513SMarkus Armbrusterbool qcrypto_cipher_supports(QCryptoCipherAlgo alg, 313d2b61ffSDaniel P. Berrangé QCryptoCipherMode mode) 323d2b61ffSDaniel P. Berrangé{ 333d2b61ffSDaniel P. Berrangé 343d2b61ffSDaniel P. Berrangé switch (mode) { 353d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_ECB: 363d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_CBC: 373d2b61ffSDaniel P. Berrangé switch (alg) { 38*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_128: 39*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_192: 40*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_256: 41*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_DES: 42*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_3DES: 433d2b61ffSDaniel P. Berrangé return true; 443d2b61ffSDaniel P. Berrangé default: 453d2b61ffSDaniel P. Berrangé return false; 463d2b61ffSDaniel P. Berrangé } 473d2b61ffSDaniel P. Berrangé#ifdef QEMU_GNUTLS_XTS 483d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_XTS: 493d2b61ffSDaniel P. Berrangé switch (alg) { 50*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_128: 51*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_256: 523d2b61ffSDaniel P. Berrangé return true; 533d2b61ffSDaniel P. Berrangé default: 543d2b61ffSDaniel P. Berrangé return false; 553d2b61ffSDaniel P. Berrangé } 563d2b61ffSDaniel P. Berrangé#endif 573d2b61ffSDaniel P. Berrangé default: 583d2b61ffSDaniel P. Berrangé return false; 593d2b61ffSDaniel P. Berrangé } 603d2b61ffSDaniel P. Berrangé} 613d2b61ffSDaniel P. Berrangé 623d2b61ffSDaniel P. Berrangétypedef struct QCryptoCipherGnutls QCryptoCipherGnutls; 633d2b61ffSDaniel P. Berrangéstruct QCryptoCipherGnutls { 643d2b61ffSDaniel P. Berrangé QCryptoCipher base; 653d2b61ffSDaniel P. Berrangé gnutls_cipher_hd_t handle; /* XTS & CBC mode */ 663d2b61ffSDaniel P. Berrangé gnutls_cipher_algorithm_t galg; /* ECB mode */ 673d2b61ffSDaniel P. Berrangé guint8 *key; /* ECB mode */ 683d2b61ffSDaniel P. Berrangé size_t nkey; /* ECB mode */ 693d2b61ffSDaniel P. Berrangé size_t blocksize; 703d2b61ffSDaniel P. Berrangé}; 713d2b61ffSDaniel P. Berrangé 723d2b61ffSDaniel P. Berrangé 733d2b61ffSDaniel P. Berrangéstatic void 743d2b61ffSDaniel P. Berrangéqcrypto_gnutls_cipher_free(QCryptoCipher *cipher) 753d2b61ffSDaniel P. Berrangé{ 763d2b61ffSDaniel P. Berrangé QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); 773d2b61ffSDaniel P. Berrangé 783d2b61ffSDaniel P. Berrangé g_free(ctx->key); 793d2b61ffSDaniel P. Berrangé if (ctx->handle) { 803d2b61ffSDaniel P. Berrangé gnutls_cipher_deinit(ctx->handle); 813d2b61ffSDaniel P. Berrangé } 823d2b61ffSDaniel P. Berrangé g_free(ctx); 833d2b61ffSDaniel P. Berrangé} 843d2b61ffSDaniel P. Berrangé 853d2b61ffSDaniel P. Berrangé 863d2b61ffSDaniel P. Berrangéstatic int 873d2b61ffSDaniel P. Berrangéqcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher, 883d2b61ffSDaniel P. Berrangé const void *in, 893d2b61ffSDaniel P. Berrangé void *out, 903d2b61ffSDaniel P. Berrangé size_t len, 913d2b61ffSDaniel P. Berrangé Error **errp) 923d2b61ffSDaniel P. Berrangé{ 933d2b61ffSDaniel P. Berrangé QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); 943d2b61ffSDaniel P. Berrangé int err; 953d2b61ffSDaniel P. Berrangé 963d2b61ffSDaniel P. Berrangé if (len % ctx->blocksize) { 973d2b61ffSDaniel P. Berrangé error_setg(errp, "Length %zu must be a multiple of block size %zu", 983d2b61ffSDaniel P. Berrangé len, ctx->blocksize); 993d2b61ffSDaniel P. Berrangé return -1; 1003d2b61ffSDaniel P. Berrangé } 1013d2b61ffSDaniel P. Berrangé 1023d2b61ffSDaniel P. Berrangé if (ctx->handle) { /* CBC / XTS mode */ 1033d2b61ffSDaniel P. Berrangé err = gnutls_cipher_encrypt2(ctx->handle, 1043d2b61ffSDaniel P. Berrangé in, len, 1053d2b61ffSDaniel P. Berrangé out, len); 1063d2b61ffSDaniel P. Berrangé if (err != 0) { 1073d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot encrypt data: %s", 1083d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1093d2b61ffSDaniel P. Berrangé return -1; 1103d2b61ffSDaniel P. Berrangé } 1113d2b61ffSDaniel P. Berrangé } else { /* ECB mode very inefficiently faked with CBC */ 1123d2b61ffSDaniel P. Berrangé g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); 1133d2b61ffSDaniel P. Berrangé while (len) { 1143d2b61ffSDaniel P. Berrangé gnutls_cipher_hd_t handle; 1153d2b61ffSDaniel P. Berrangé gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; 1165f6d4f79SPhilippe Mathieu-Daudé err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); 1173d2b61ffSDaniel P. Berrangé if (err != 0) { 1183d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot initialize cipher: %s", 1193d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1203d2b61ffSDaniel P. Berrangé return -1; 1213d2b61ffSDaniel P. Berrangé } 1223d2b61ffSDaniel P. Berrangé 1233d2b61ffSDaniel P. Berrangé gnutls_cipher_set_iv(handle, iv, ctx->blocksize); 1243d2b61ffSDaniel P. Berrangé 1253d2b61ffSDaniel P. Berrangé err = gnutls_cipher_encrypt2(handle, 1263d2b61ffSDaniel P. Berrangé in, ctx->blocksize, 1273d2b61ffSDaniel P. Berrangé out, ctx->blocksize); 1283d2b61ffSDaniel P. Berrangé if (err != 0) { 1293d2b61ffSDaniel P. Berrangé gnutls_cipher_deinit(handle); 1303d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot encrypt data: %s", 1313d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1323d2b61ffSDaniel P. Berrangé return -1; 1333d2b61ffSDaniel P. Berrangé } 1343d2b61ffSDaniel P. Berrangé gnutls_cipher_deinit(handle); 1353d2b61ffSDaniel P. Berrangé 1363d2b61ffSDaniel P. Berrangé len -= ctx->blocksize; 1373d2b61ffSDaniel P. Berrangé in += ctx->blocksize; 1383d2b61ffSDaniel P. Berrangé out += ctx->blocksize; 1393d2b61ffSDaniel P. Berrangé } 1403d2b61ffSDaniel P. Berrangé } 1413d2b61ffSDaniel P. Berrangé 1423d2b61ffSDaniel P. Berrangé return 0; 1433d2b61ffSDaniel P. Berrangé} 1443d2b61ffSDaniel P. Berrangé 1453d2b61ffSDaniel P. Berrangé 1463d2b61ffSDaniel P. Berrangéstatic int 1473d2b61ffSDaniel P. Berrangéqcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher, 1483d2b61ffSDaniel P. Berrangé const void *in, 1493d2b61ffSDaniel P. Berrangé void *out, 1503d2b61ffSDaniel P. Berrangé size_t len, 1513d2b61ffSDaniel P. Berrangé Error **errp) 1523d2b61ffSDaniel P. Berrangé{ 1533d2b61ffSDaniel P. Berrangé QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); 1543d2b61ffSDaniel P. Berrangé int err; 1553d2b61ffSDaniel P. Berrangé 1563d2b61ffSDaniel P. Berrangé if (len % ctx->blocksize) { 1573d2b61ffSDaniel P. Berrangé error_setg(errp, "Length %zu must be a multiple of block size %zu", 1583d2b61ffSDaniel P. Berrangé len, ctx->blocksize); 1593d2b61ffSDaniel P. Berrangé return -1; 1603d2b61ffSDaniel P. Berrangé } 1613d2b61ffSDaniel P. Berrangé 1623d2b61ffSDaniel P. Berrangé if (ctx->handle) { /* CBC / XTS mode */ 1633d2b61ffSDaniel P. Berrangé err = gnutls_cipher_decrypt2(ctx->handle, 1643d2b61ffSDaniel P. Berrangé in, len, 1653d2b61ffSDaniel P. Berrangé out, len); 1663d2b61ffSDaniel P. Berrangé 1673d2b61ffSDaniel P. Berrangé if (err != 0) { 1683d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot decrypt data: %s", 1693d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1703d2b61ffSDaniel P. Berrangé return -1; 1713d2b61ffSDaniel P. Berrangé } 1723d2b61ffSDaniel P. Berrangé } else { /* ECB mode very inefficiently faked with CBC */ 1733d2b61ffSDaniel P. Berrangé g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); 1743d2b61ffSDaniel P. Berrangé while (len) { 1753d2b61ffSDaniel P. Berrangé gnutls_cipher_hd_t handle; 1763d2b61ffSDaniel P. Berrangé gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey }; 1775f6d4f79SPhilippe Mathieu-Daudé err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL); 1783d2b61ffSDaniel P. Berrangé if (err != 0) { 1793d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot initialize cipher: %s", 1803d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1813d2b61ffSDaniel P. Berrangé return -1; 1823d2b61ffSDaniel P. Berrangé } 1833d2b61ffSDaniel P. Berrangé 1843d2b61ffSDaniel P. Berrangé gnutls_cipher_set_iv(handle, iv, ctx->blocksize); 1853d2b61ffSDaniel P. Berrangé 1863d2b61ffSDaniel P. Berrangé err = gnutls_cipher_decrypt2(handle, 1873d2b61ffSDaniel P. Berrangé in, ctx->blocksize, 1883d2b61ffSDaniel P. Berrangé out, ctx->blocksize); 1893d2b61ffSDaniel P. Berrangé if (err != 0) { 1903d2b61ffSDaniel P. Berrangé gnutls_cipher_deinit(handle); 1913d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot encrypt data: %s", 1923d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 1933d2b61ffSDaniel P. Berrangé return -1; 1943d2b61ffSDaniel P. Berrangé } 1953d2b61ffSDaniel P. Berrangé gnutls_cipher_deinit(handle); 1963d2b61ffSDaniel P. Berrangé 1973d2b61ffSDaniel P. Berrangé len -= ctx->blocksize; 1983d2b61ffSDaniel P. Berrangé in += ctx->blocksize; 1993d2b61ffSDaniel P. Berrangé out += ctx->blocksize; 2003d2b61ffSDaniel P. Berrangé } 2013d2b61ffSDaniel P. Berrangé } 2023d2b61ffSDaniel P. Berrangé 2033d2b61ffSDaniel P. Berrangé return 0; 2043d2b61ffSDaniel P. Berrangé} 2053d2b61ffSDaniel P. Berrangé 2063d2b61ffSDaniel P. Berrangéstatic int 2073d2b61ffSDaniel P. Berrangéqcrypto_gnutls_cipher_setiv(QCryptoCipher *cipher, 2083d2b61ffSDaniel P. Berrangé const uint8_t *iv, size_t niv, 2093d2b61ffSDaniel P. Berrangé Error **errp) 2103d2b61ffSDaniel P. Berrangé{ 2113d2b61ffSDaniel P. Berrangé QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); 2123d2b61ffSDaniel P. Berrangé 2133d2b61ffSDaniel P. Berrangé if (niv != ctx->blocksize) { 2143d2b61ffSDaniel P. Berrangé error_setg(errp, "Expected IV size %zu not %zu", 2153d2b61ffSDaniel P. Berrangé ctx->blocksize, niv); 2163d2b61ffSDaniel P. Berrangé return -1; 2173d2b61ffSDaniel P. Berrangé } 2183d2b61ffSDaniel P. Berrangé 2193d2b61ffSDaniel P. Berrangé gnutls_cipher_set_iv(ctx->handle, (unsigned char *)iv, niv); 2203d2b61ffSDaniel P. Berrangé 2213d2b61ffSDaniel P. Berrangé return 0; 2223d2b61ffSDaniel P. Berrangé} 2233d2b61ffSDaniel P. Berrangé 2243d2b61ffSDaniel P. Berrangé 2253d2b61ffSDaniel P. Berrangéstatic struct QCryptoCipherDriver gnutls_driver = { 2263d2b61ffSDaniel P. Berrangé .cipher_encrypt = qcrypto_gnutls_cipher_encrypt, 2273d2b61ffSDaniel P. Berrangé .cipher_decrypt = qcrypto_gnutls_cipher_decrypt, 2283d2b61ffSDaniel P. Berrangé .cipher_setiv = qcrypto_gnutls_cipher_setiv, 2293d2b61ffSDaniel P. Berrangé .cipher_free = qcrypto_gnutls_cipher_free, 2303d2b61ffSDaniel P. Berrangé}; 2313d2b61ffSDaniel P. Berrangé 232*a092c513SMarkus Armbrusterstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, 2333d2b61ffSDaniel P. Berrangé QCryptoCipherMode mode, 2343d2b61ffSDaniel P. Berrangé const uint8_t *key, 2353d2b61ffSDaniel P. Berrangé size_t nkey, 2363d2b61ffSDaniel P. Berrangé Error **errp) 2373d2b61ffSDaniel P. Berrangé{ 2383d2b61ffSDaniel P. Berrangé QCryptoCipherGnutls *ctx; 2393d2b61ffSDaniel P. Berrangé gnutls_datum_t gkey = { (unsigned char *)key, nkey }; 2403d2b61ffSDaniel P. Berrangé gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN; 2413d2b61ffSDaniel P. Berrangé int err; 2423d2b61ffSDaniel P. Berrangé 2433d2b61ffSDaniel P. Berrangé switch (mode) { 2443d2b61ffSDaniel P. Berrangé#ifdef QEMU_GNUTLS_XTS 2453d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_XTS: 2463d2b61ffSDaniel P. Berrangé switch (alg) { 247*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_128: 2483d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_AES_128_XTS; 2493d2b61ffSDaniel P. Berrangé break; 250*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_256: 2513d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_AES_256_XTS; 2523d2b61ffSDaniel P. Berrangé break; 2533d2b61ffSDaniel P. Berrangé default: 2543d2b61ffSDaniel P. Berrangé break; 2553d2b61ffSDaniel P. Berrangé } 2563d2b61ffSDaniel P. Berrangé break; 2573d2b61ffSDaniel P. Berrangé#endif 2583d2b61ffSDaniel P. Berrangé 2593d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_ECB: 2603d2b61ffSDaniel P. Berrangé case QCRYPTO_CIPHER_MODE_CBC: 2613d2b61ffSDaniel P. Berrangé switch (alg) { 262*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_128: 2633d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_AES_128_CBC; 2643d2b61ffSDaniel P. Berrangé break; 265*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_192: 2663d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_AES_192_CBC; 2673d2b61ffSDaniel P. Berrangé break; 268*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_256: 2693d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_AES_256_CBC; 2703d2b61ffSDaniel P. Berrangé break; 271*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_DES: 2723d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_DES_CBC; 2733d2b61ffSDaniel P. Berrangé break; 274*a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_3DES: 2753d2b61ffSDaniel P. Berrangé galg = GNUTLS_CIPHER_3DES_CBC; 2763d2b61ffSDaniel P. Berrangé break; 2773d2b61ffSDaniel P. Berrangé default: 2783d2b61ffSDaniel P. Berrangé break; 2793d2b61ffSDaniel P. Berrangé } 2803d2b61ffSDaniel P. Berrangé break; 2813d2b61ffSDaniel P. Berrangé default: 2823d2b61ffSDaniel P. Berrangé break; 2833d2b61ffSDaniel P. Berrangé } 2843d2b61ffSDaniel P. Berrangé 2853d2b61ffSDaniel P. Berrangé if (galg == GNUTLS_CIPHER_UNKNOWN) { 2863d2b61ffSDaniel P. Berrangé error_setg(errp, "Unsupported cipher algorithm %s with %s mode", 287*a092c513SMarkus Armbruster QCryptoCipherAlgo_str(alg), 2883d2b61ffSDaniel P. Berrangé QCryptoCipherMode_str(mode)); 2893d2b61ffSDaniel P. Berrangé return NULL; 2903d2b61ffSDaniel P. Berrangé } 2913d2b61ffSDaniel P. Berrangé 2923d2b61ffSDaniel P. Berrangé if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { 2933d2b61ffSDaniel P. Berrangé return NULL; 2943d2b61ffSDaniel P. Berrangé } 2953d2b61ffSDaniel P. Berrangé 2963d2b61ffSDaniel P. Berrangé ctx = g_new0(QCryptoCipherGnutls, 1); 2973d2b61ffSDaniel P. Berrangé ctx->base.driver = &gnutls_driver; 2983d2b61ffSDaniel P. Berrangé 2993d2b61ffSDaniel P. Berrangé if (mode == QCRYPTO_CIPHER_MODE_ECB) { 3003d2b61ffSDaniel P. Berrangé ctx->key = g_new0(guint8, nkey); 3013d2b61ffSDaniel P. Berrangé memcpy(ctx->key, key, nkey); 3023d2b61ffSDaniel P. Berrangé ctx->nkey = nkey; 3033d2b61ffSDaniel P. Berrangé ctx->galg = galg; 3043d2b61ffSDaniel P. Berrangé } else { 3053d2b61ffSDaniel P. Berrangé err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL); 3063d2b61ffSDaniel P. Berrangé if (err != 0) { 3073d2b61ffSDaniel P. Berrangé error_setg(errp, "Cannot initialize cipher: %s", 3083d2b61ffSDaniel P. Berrangé gnutls_strerror(err)); 3093d2b61ffSDaniel P. Berrangé goto error; 3103d2b61ffSDaniel P. Berrangé } 3113d2b61ffSDaniel P. Berrangé } 3123d2b61ffSDaniel P. Berrangé 313*a092c513SMarkus Armbruster if (alg == QCRYPTO_CIPHER_ALGO_DES || 314*a092c513SMarkus Armbruster alg == QCRYPTO_CIPHER_ALGO_3DES) 3153d2b61ffSDaniel P. Berrangé ctx->blocksize = 8; 3163d2b61ffSDaniel P. Berrangé else 3173d2b61ffSDaniel P. Berrangé ctx->blocksize = 16; 3183d2b61ffSDaniel P. Berrangé 3193d2b61ffSDaniel P. Berrangé /* 3203d2b61ffSDaniel P. Berrangé * Our API contract for requires iv to be optional 3213d2b61ffSDaniel P. Berrangé * but nettle gets unhappy when called by gnutls 3223d2b61ffSDaniel P. Berrangé * in this case, so we just force set a default 3233d2b61ffSDaniel P. Berrangé * all-zeros IV, to match behaviour of other backends. 3243d2b61ffSDaniel P. Berrangé */ 3253d2b61ffSDaniel P. Berrangé if (mode != QCRYPTO_CIPHER_MODE_ECB) { 3263d2b61ffSDaniel P. Berrangé g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize); 3273d2b61ffSDaniel P. Berrangé gnutls_cipher_set_iv(ctx->handle, iv, ctx->blocksize); 3283d2b61ffSDaniel P. Berrangé } 3293d2b61ffSDaniel P. Berrangé 3303d2b61ffSDaniel P. Berrangé return &ctx->base; 3313d2b61ffSDaniel P. Berrangé 3323d2b61ffSDaniel P. Berrangé error: 3333d2b61ffSDaniel P. Berrangé qcrypto_gnutls_cipher_free(&ctx->base); 3343d2b61ffSDaniel P. Berrangé return NULL; 3353d2b61ffSDaniel P. Berrangé} 336