xref: /openbmc/qemu/crypto/cipher-gnutls.c.inc (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
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