xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
16d92bdf4SRichard Henderson/*
26d92bdf4SRichard Henderson * QEMU Crypto cipher libgcrypt algorithms
36d92bdf4SRichard Henderson *
46d92bdf4SRichard Henderson * Copyright (c) 2015 Red Hat, Inc.
56d92bdf4SRichard Henderson *
66d92bdf4SRichard Henderson * This library is free software; you can redistribute it and/or
76d92bdf4SRichard Henderson * modify it under the terms of the GNU Lesser General Public
86d92bdf4SRichard Henderson * License as published by the Free Software Foundation; either
96d92bdf4SRichard Henderson * version 2.1 of the License, or (at your option) any later version.
106d92bdf4SRichard Henderson *
116d92bdf4SRichard Henderson * This library is distributed in the hope that it will be useful,
126d92bdf4SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of
136d92bdf4SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146d92bdf4SRichard Henderson * Lesser General Public License for more details.
156d92bdf4SRichard Henderson *
166d92bdf4SRichard Henderson * You should have received a copy of the GNU Lesser General Public
176d92bdf4SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186d92bdf4SRichard Henderson *
196d92bdf4SRichard Henderson */
206d92bdf4SRichard Henderson
216d92bdf4SRichard Henderson#include <gcrypt.h>
226d92bdf4SRichard Henderson
23*a092c513SMarkus Armbrusterstatic int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgo alg)
24eac57306SDaniel P. Berrangé{
25eac57306SDaniel P. Berrangé    switch (alg) {
26*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_DES:
27eac57306SDaniel P. Berrangé        return GCRY_CIPHER_DES;
28*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_3DES:
29eac57306SDaniel P. Berrangé        return GCRY_CIPHER_3DES;
30*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_128:
31eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES128;
32*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_192:
33eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES192;
34*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_256:
35eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES256;
36*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_CAST5_128:
37eac57306SDaniel P. Berrangé        return GCRY_CIPHER_CAST5;
38*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_128:
39eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT128;
40*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_192:
41eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT192;
42*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_256:
43eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT256;
44*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
45eac57306SDaniel P. Berrangé        return GCRY_CIPHER_TWOFISH128;
46*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
47eac57306SDaniel P. Berrangé        return GCRY_CIPHER_TWOFISH;
48eac57306SDaniel P. Berrangé#ifdef CONFIG_CRYPTO_SM4
49*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SM4:
50eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SM4;
51eac57306SDaniel P. Berrangé#endif
52eac57306SDaniel P. Berrangé    default:
53eac57306SDaniel P. Berrangé        return GCRY_CIPHER_NONE;
54eac57306SDaniel P. Berrangé    }
55eac57306SDaniel P. Berrangé}
56eac57306SDaniel P. Berrangé
57eac57306SDaniel P. Berrangéstatic int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
58eac57306SDaniel P. Berrangé{
59eac57306SDaniel P. Berrangé    switch (mode) {
60eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_ECB:
61eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_ECB;
62eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_XTS:
63eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_XTS;
64eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_CBC:
65eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_CBC;
66eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_CTR:
67eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_CTR;
68eac57306SDaniel P. Berrangé    default:
69eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_NONE;
70eac57306SDaniel P. Berrangé    }
71eac57306SDaniel P. Berrangé}
72eac57306SDaniel P. Berrangé
73*a092c513SMarkus Armbrusterbool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
746d92bdf4SRichard Henderson                             QCryptoCipherMode mode)
756d92bdf4SRichard Henderson{
766d92bdf4SRichard Henderson    switch (alg) {
77*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_DES:
78*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_3DES:
79*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_128:
80*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_192:
81*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_256:
82*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_CAST5_128:
83*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_128:
84*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_192:
85*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SERPENT_256:
86*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
87*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
8852ed9f45SHyman Huang#ifdef CONFIG_CRYPTO_SM4
89*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_SM4:
9052ed9f45SHyman Huang#endif
916d92bdf4SRichard Henderson        break;
926d92bdf4SRichard Henderson    default:
936d92bdf4SRichard Henderson        return false;
946d92bdf4SRichard Henderson    }
956d92bdf4SRichard Henderson
96e503fc55SDaniel P. Berrangé    if (gcry_cipher_algo_info(qcrypto_cipher_alg_to_gcry_alg(alg),
97e503fc55SDaniel P. Berrangé                              GCRYCTL_TEST_ALGO, NULL, NULL) != 0) {
98e503fc55SDaniel P. Berrangé        return false;
99e503fc55SDaniel P. Berrangé    }
100e503fc55SDaniel P. Berrangé
1016d92bdf4SRichard Henderson    switch (mode) {
1026d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
1036d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
1046d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
1056d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
1066d92bdf4SRichard Henderson        return true;
1076d92bdf4SRichard Henderson    default:
1086d92bdf4SRichard Henderson        return false;
1096d92bdf4SRichard Henderson    }
1106d92bdf4SRichard Henderson}
1116d92bdf4SRichard Henderson
1121b010d93SRichard Hendersontypedef struct QCryptoCipherGcrypt {
1133eedf5ccSRichard Henderson    QCryptoCipher base;
1146d92bdf4SRichard Henderson    gcry_cipher_hd_t handle;
1156d92bdf4SRichard Henderson    size_t blocksize;
1161b010d93SRichard Henderson} QCryptoCipherGcrypt;
1176d92bdf4SRichard Henderson
1181b010d93SRichard Henderson
1191b010d93SRichard Hendersonstatic void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
1206d92bdf4SRichard Henderson{
1211b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1226d92bdf4SRichard Henderson
1236d92bdf4SRichard Henderson    gcry_cipher_close(ctx->handle);
1246d92bdf4SRichard Henderson    g_free(ctx);
1256d92bdf4SRichard Henderson}
1266d92bdf4SRichard Henderson
1271b010d93SRichard Hendersonstatic int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
1281b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
1291b010d93SRichard Henderson{
1301b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1311b010d93SRichard Henderson    gcry_error_t err;
1321b010d93SRichard Henderson
1331b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
1341b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
1351b010d93SRichard Henderson                   len, ctx->blocksize);
1361b010d93SRichard Henderson        return -1;
1371b010d93SRichard Henderson    }
1381b010d93SRichard Henderson
1391b010d93SRichard Henderson    err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
1401b010d93SRichard Henderson    if (err != 0) {
1411b010d93SRichard Henderson        error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
1421b010d93SRichard Henderson        return -1;
1431b010d93SRichard Henderson    }
1441b010d93SRichard Henderson
1451b010d93SRichard Henderson    return 0;
1461b010d93SRichard Henderson}
1471b010d93SRichard Henderson
1481b010d93SRichard Henderson
1491b010d93SRichard Hendersonstatic int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
1501b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
1511b010d93SRichard Henderson{
1521b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1531b010d93SRichard Henderson    gcry_error_t err;
1541b010d93SRichard Henderson
1551b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
1561b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
1571b010d93SRichard Henderson                   len, ctx->blocksize);
1581b010d93SRichard Henderson        return -1;
1591b010d93SRichard Henderson    }
1601b010d93SRichard Henderson
1611b010d93SRichard Henderson    err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
1621b010d93SRichard Henderson    if (err != 0) {
1631b010d93SRichard Henderson        error_setg(errp, "Cannot decrypt data: %s",
1641b010d93SRichard Henderson                   gcry_strerror(err));
1651b010d93SRichard Henderson        return -1;
1661b010d93SRichard Henderson    }
1671b010d93SRichard Henderson
1681b010d93SRichard Henderson    return 0;
1691b010d93SRichard Henderson}
1701b010d93SRichard Henderson
1711b010d93SRichard Hendersonstatic int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
1721b010d93SRichard Henderson                                const uint8_t *iv, size_t niv,
1731b010d93SRichard Henderson                                Error **errp)
1741b010d93SRichard Henderson{
1751b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1761b010d93SRichard Henderson    gcry_error_t err;
1771b010d93SRichard Henderson
1781b010d93SRichard Henderson    if (niv != ctx->blocksize) {
1791b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
1801b010d93SRichard Henderson                   ctx->blocksize, niv);
1811b010d93SRichard Henderson        return -1;
1821b010d93SRichard Henderson    }
1831b010d93SRichard Henderson
1841b010d93SRichard Henderson    gcry_cipher_reset(ctx->handle);
1851b010d93SRichard Henderson    err = gcry_cipher_setiv(ctx->handle, iv, niv);
1861b010d93SRichard Henderson    if (err != 0) {
1871b010d93SRichard Henderson        error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
1881b010d93SRichard Henderson        return -1;
1891b010d93SRichard Henderson    }
1901b010d93SRichard Henderson
1911b010d93SRichard Henderson    return 0;
1921b010d93SRichard Henderson}
1931b010d93SRichard Henderson
1941b010d93SRichard Hendersonstatic int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
1951b010d93SRichard Henderson                                    const uint8_t *iv, size_t niv,
1961b010d93SRichard Henderson                                    Error **errp)
1971b010d93SRichard Henderson{
1981b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1991b010d93SRichard Henderson    gcry_error_t err;
2001b010d93SRichard Henderson
2011b010d93SRichard Henderson    if (niv != ctx->blocksize) {
2021b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
2031b010d93SRichard Henderson                   ctx->blocksize, niv);
2041b010d93SRichard Henderson        return -1;
2051b010d93SRichard Henderson    }
2061b010d93SRichard Henderson
2071b010d93SRichard Henderson    err = gcry_cipher_setctr(ctx->handle, iv, niv);
2081b010d93SRichard Henderson    if (err != 0) {
2091b010d93SRichard Henderson        error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
2101b010d93SRichard Henderson        return -1;
2111b010d93SRichard Henderson    }
2121b010d93SRichard Henderson
2131b010d93SRichard Henderson    return 0;
2141b010d93SRichard Henderson}
2151b010d93SRichard Henderson
2161b010d93SRichard Henderson
2171b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
2181b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
2191b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
2201b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_setiv,
2211b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
2221b010d93SRichard Henderson};
2231b010d93SRichard Henderson
2241b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
2251b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
2261b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
2271b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
2281b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
2291b010d93SRichard Henderson};
2301b010d93SRichard Henderson
231*a092c513SMarkus Armbrusterstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
2326d92bdf4SRichard Henderson                                             QCryptoCipherMode mode,
2336d92bdf4SRichard Henderson                                             const uint8_t *key,
2346d92bdf4SRichard Henderson                                             size_t nkey,
2356d92bdf4SRichard Henderson                                             Error **errp)
2366d92bdf4SRichard Henderson{
2376d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx;
2381b010d93SRichard Henderson    const QCryptoCipherDriver *drv;
2396d92bdf4SRichard Henderson    gcry_error_t err;
2406d92bdf4SRichard Henderson    int gcryalg, gcrymode;
2416d92bdf4SRichard Henderson
2426d92bdf4SRichard Henderson    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
2436d92bdf4SRichard Henderson        return NULL;
2446d92bdf4SRichard Henderson    }
2456d92bdf4SRichard Henderson
246eac57306SDaniel P. Berrangé    gcryalg = qcrypto_cipher_alg_to_gcry_alg(alg);
247eac57306SDaniel P. Berrangé    if (gcryalg == GCRY_CIPHER_NONE) {
2486d92bdf4SRichard Henderson        error_setg(errp, "Unsupported cipher algorithm %s",
249*a092c513SMarkus Armbruster                   QCryptoCipherAlgo_str(alg));
2506d92bdf4SRichard Henderson        return NULL;
2516d92bdf4SRichard Henderson    }
2526d92bdf4SRichard Henderson
253eac57306SDaniel P. Berrangé    gcrymode = qcrypto_cipher_mode_to_gcry_mode(mode);
254eac57306SDaniel P. Berrangé    if (gcrymode == GCRY_CIPHER_MODE_NONE) {
2551b010d93SRichard Henderson        error_setg(errp, "Unsupported cipher mode %s",
2561b010d93SRichard Henderson                   QCryptoCipherMode_str(mode));
2571b010d93SRichard Henderson        return NULL;
2581b010d93SRichard Henderson    }
2591b010d93SRichard Henderson
260eac57306SDaniel P. Berrangé    if (mode == QCRYPTO_CIPHER_MODE_CTR) {
261eac57306SDaniel P. Berrangé        drv = &qcrypto_gcrypt_ctr_driver;
262eac57306SDaniel P. Berrangé    } else {
263eac57306SDaniel P. Berrangé        drv = &qcrypto_gcrypt_driver;
264eac57306SDaniel P. Berrangé    }
265eac57306SDaniel P. Berrangé
2666d92bdf4SRichard Henderson    ctx = g_new0(QCryptoCipherGcrypt, 1);
2671b010d93SRichard Henderson    ctx->base.driver = drv;
2686d92bdf4SRichard Henderson
2696d92bdf4SRichard Henderson    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
2706d92bdf4SRichard Henderson    if (err != 0) {
2716d92bdf4SRichard Henderson        error_setg(errp, "Cannot initialize cipher: %s",
2726d92bdf4SRichard Henderson                   gcry_strerror(err));
2736d92bdf4SRichard Henderson        goto error;
2746d92bdf4SRichard Henderson    }
2751b010d93SRichard Henderson    ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
2761b010d93SRichard Henderson
2776d92bdf4SRichard Henderson    err = gcry_cipher_setkey(ctx->handle, key, nkey);
2786d92bdf4SRichard Henderson    if (err != 0) {
2791b010d93SRichard Henderson        error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
2806d92bdf4SRichard Henderson        goto error;
2816d92bdf4SRichard Henderson    }
2826d92bdf4SRichard Henderson
2833eedf5ccSRichard Henderson    return &ctx->base;
2846d92bdf4SRichard Henderson
2856d92bdf4SRichard Henderson error:
2861b010d93SRichard Henderson    gcry_cipher_close(ctx->handle);
2871b010d93SRichard Henderson    g_free(ctx);
2886d92bdf4SRichard Henderson    return NULL;
2896d92bdf4SRichard Henderson}
290