xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision eac57306d89facbcacdb814833b57a8c9ed18d62)
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*eac57306SDaniel P. Berrangéstatic int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgorithm alg)
24*eac57306SDaniel P. Berrangé{
25*eac57306SDaniel P. Berrangé    switch (alg) {
26*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_DES:
27*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_DES;
28*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_3DES:
29*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_3DES;
30*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_AES_128:
31*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES128;
32*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_AES_192:
33*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES192;
34*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_AES_256:
35*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_AES256;
36*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_CAST5_128:
37*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_CAST5;
38*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_SERPENT_128:
39*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT128;
40*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_SERPENT_192:
41*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT192;
42*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_SERPENT_256:
43*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SERPENT256;
44*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
45*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_TWOFISH128;
46*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
47*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_TWOFISH;
48*eac57306SDaniel P. Berrangé#ifdef CONFIG_CRYPTO_SM4
49*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_SM4:
50*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_SM4;
51*eac57306SDaniel P. Berrangé#endif
52*eac57306SDaniel P. Berrangé    default:
53*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_NONE;
54*eac57306SDaniel P. Berrangé    }
55*eac57306SDaniel P. Berrangé}
56*eac57306SDaniel P. Berrangé
57*eac57306SDaniel P. Berrangéstatic int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
58*eac57306SDaniel P. Berrangé{
59*eac57306SDaniel P. Berrangé    switch (mode) {
60*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_ECB:
61*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_ECB;
62*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_XTS:
63*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_XTS;
64*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_CBC:
65*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_CBC;
66*eac57306SDaniel P. Berrangé    case QCRYPTO_CIPHER_MODE_CTR:
67*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_CTR;
68*eac57306SDaniel P. Berrangé    default:
69*eac57306SDaniel P. Berrangé        return GCRY_CIPHER_MODE_NONE;
70*eac57306SDaniel P. Berrangé    }
71*eac57306SDaniel P. Berrangé}
72*eac57306SDaniel P. Berrangé
736d92bdf4SRichard Hendersonbool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
746d92bdf4SRichard Henderson                             QCryptoCipherMode mode)
756d92bdf4SRichard Henderson{
766d92bdf4SRichard Henderson    switch (alg) {
7783bee4b5SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_DES:
786d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_3DES:
796d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_128:
806d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_192:
816d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_256:
826d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_CAST5_128:
836d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_128:
846d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_192:
856d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_256:
866d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
876d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
8852ed9f45SHyman Huang#ifdef CONFIG_CRYPTO_SM4
8952ed9f45SHyman Huang    case QCRYPTO_CIPHER_ALG_SM4:
9052ed9f45SHyman Huang#endif
916d92bdf4SRichard Henderson        break;
926d92bdf4SRichard Henderson    default:
936d92bdf4SRichard Henderson        return false;
946d92bdf4SRichard Henderson    }
956d92bdf4SRichard Henderson
966d92bdf4SRichard Henderson    switch (mode) {
976d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
986d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
996d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
1006d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
1016d92bdf4SRichard Henderson        return true;
1026d92bdf4SRichard Henderson    default:
1036d92bdf4SRichard Henderson        return false;
1046d92bdf4SRichard Henderson    }
1056d92bdf4SRichard Henderson}
1066d92bdf4SRichard Henderson
1071b010d93SRichard Hendersontypedef struct QCryptoCipherGcrypt {
1083eedf5ccSRichard Henderson    QCryptoCipher base;
1096d92bdf4SRichard Henderson    gcry_cipher_hd_t handle;
1106d92bdf4SRichard Henderson    size_t blocksize;
1111b010d93SRichard Henderson} QCryptoCipherGcrypt;
1126d92bdf4SRichard Henderson
1131b010d93SRichard Henderson
1141b010d93SRichard Hendersonstatic void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
1156d92bdf4SRichard Henderson{
1161b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1176d92bdf4SRichard Henderson
1186d92bdf4SRichard Henderson    gcry_cipher_close(ctx->handle);
1196d92bdf4SRichard Henderson    g_free(ctx);
1206d92bdf4SRichard Henderson}
1216d92bdf4SRichard Henderson
1221b010d93SRichard Hendersonstatic int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
1231b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
1241b010d93SRichard Henderson{
1251b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1261b010d93SRichard Henderson    gcry_error_t err;
1271b010d93SRichard Henderson
1281b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
1291b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
1301b010d93SRichard Henderson                   len, ctx->blocksize);
1311b010d93SRichard Henderson        return -1;
1321b010d93SRichard Henderson    }
1331b010d93SRichard Henderson
1341b010d93SRichard Henderson    err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
1351b010d93SRichard Henderson    if (err != 0) {
1361b010d93SRichard Henderson        error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
1371b010d93SRichard Henderson        return -1;
1381b010d93SRichard Henderson    }
1391b010d93SRichard Henderson
1401b010d93SRichard Henderson    return 0;
1411b010d93SRichard Henderson}
1421b010d93SRichard Henderson
1431b010d93SRichard Henderson
1441b010d93SRichard Hendersonstatic int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
1451b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
1461b010d93SRichard Henderson{
1471b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1481b010d93SRichard Henderson    gcry_error_t err;
1491b010d93SRichard Henderson
1501b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
1511b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
1521b010d93SRichard Henderson                   len, ctx->blocksize);
1531b010d93SRichard Henderson        return -1;
1541b010d93SRichard Henderson    }
1551b010d93SRichard Henderson
1561b010d93SRichard Henderson    err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
1571b010d93SRichard Henderson    if (err != 0) {
1581b010d93SRichard Henderson        error_setg(errp, "Cannot decrypt data: %s",
1591b010d93SRichard Henderson                   gcry_strerror(err));
1601b010d93SRichard Henderson        return -1;
1611b010d93SRichard Henderson    }
1621b010d93SRichard Henderson
1631b010d93SRichard Henderson    return 0;
1641b010d93SRichard Henderson}
1651b010d93SRichard Henderson
1661b010d93SRichard Hendersonstatic int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
1671b010d93SRichard Henderson                                const uint8_t *iv, size_t niv,
1681b010d93SRichard Henderson                                Error **errp)
1691b010d93SRichard Henderson{
1701b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1711b010d93SRichard Henderson    gcry_error_t err;
1721b010d93SRichard Henderson
1731b010d93SRichard Henderson    if (niv != ctx->blocksize) {
1741b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
1751b010d93SRichard Henderson                   ctx->blocksize, niv);
1761b010d93SRichard Henderson        return -1;
1771b010d93SRichard Henderson    }
1781b010d93SRichard Henderson
1791b010d93SRichard Henderson    gcry_cipher_reset(ctx->handle);
1801b010d93SRichard Henderson    err = gcry_cipher_setiv(ctx->handle, iv, niv);
1811b010d93SRichard Henderson    if (err != 0) {
1821b010d93SRichard Henderson        error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
1831b010d93SRichard Henderson        return -1;
1841b010d93SRichard Henderson    }
1851b010d93SRichard Henderson
1861b010d93SRichard Henderson    return 0;
1871b010d93SRichard Henderson}
1881b010d93SRichard Henderson
1891b010d93SRichard Hendersonstatic int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
1901b010d93SRichard Henderson                                    const uint8_t *iv, size_t niv,
1911b010d93SRichard Henderson                                    Error **errp)
1921b010d93SRichard Henderson{
1931b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1941b010d93SRichard Henderson    gcry_error_t err;
1951b010d93SRichard Henderson
1961b010d93SRichard Henderson    if (niv != ctx->blocksize) {
1971b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
1981b010d93SRichard Henderson                   ctx->blocksize, niv);
1991b010d93SRichard Henderson        return -1;
2001b010d93SRichard Henderson    }
2011b010d93SRichard Henderson
2021b010d93SRichard Henderson    err = gcry_cipher_setctr(ctx->handle, iv, niv);
2031b010d93SRichard Henderson    if (err != 0) {
2041b010d93SRichard Henderson        error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
2051b010d93SRichard Henderson        return -1;
2061b010d93SRichard Henderson    }
2071b010d93SRichard Henderson
2081b010d93SRichard Henderson    return 0;
2091b010d93SRichard Henderson}
2101b010d93SRichard Henderson
2111b010d93SRichard Henderson
2121b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
2131b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
2141b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
2151b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_setiv,
2161b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
2171b010d93SRichard Henderson};
2181b010d93SRichard Henderson
2191b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
2201b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
2211b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
2221b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
2231b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
2241b010d93SRichard Henderson};
2251b010d93SRichard Henderson
2263eedf5ccSRichard Hendersonstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
2276d92bdf4SRichard Henderson                                             QCryptoCipherMode mode,
2286d92bdf4SRichard Henderson                                             const uint8_t *key,
2296d92bdf4SRichard Henderson                                             size_t nkey,
2306d92bdf4SRichard Henderson                                             Error **errp)
2316d92bdf4SRichard Henderson{
2326d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx;
2331b010d93SRichard Henderson    const QCryptoCipherDriver *drv;
2346d92bdf4SRichard Henderson    gcry_error_t err;
2356d92bdf4SRichard Henderson    int gcryalg, gcrymode;
2366d92bdf4SRichard Henderson
2376d92bdf4SRichard Henderson    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
2386d92bdf4SRichard Henderson        return NULL;
2396d92bdf4SRichard Henderson    }
2406d92bdf4SRichard Henderson
241*eac57306SDaniel P. Berrangé    gcryalg = qcrypto_cipher_alg_to_gcry_alg(alg);
242*eac57306SDaniel P. Berrangé    if (gcryalg == GCRY_CIPHER_NONE) {
2436d92bdf4SRichard Henderson        error_setg(errp, "Unsupported cipher algorithm %s",
2446d92bdf4SRichard Henderson                   QCryptoCipherAlgorithm_str(alg));
2456d92bdf4SRichard Henderson        return NULL;
2466d92bdf4SRichard Henderson    }
2476d92bdf4SRichard Henderson
248*eac57306SDaniel P. Berrangé    gcrymode = qcrypto_cipher_mode_to_gcry_mode(mode);
249*eac57306SDaniel P. Berrangé    if (gcrymode == GCRY_CIPHER_MODE_NONE) {
2501b010d93SRichard Henderson        error_setg(errp, "Unsupported cipher mode %s",
2511b010d93SRichard Henderson                   QCryptoCipherMode_str(mode));
2521b010d93SRichard Henderson        return NULL;
2531b010d93SRichard Henderson    }
2541b010d93SRichard Henderson
255*eac57306SDaniel P. Berrangé    if (mode == QCRYPTO_CIPHER_MODE_CTR) {
256*eac57306SDaniel P. Berrangé        drv = &qcrypto_gcrypt_ctr_driver;
257*eac57306SDaniel P. Berrangé    } else {
258*eac57306SDaniel P. Berrangé        drv = &qcrypto_gcrypt_driver;
259*eac57306SDaniel P. Berrangé    }
260*eac57306SDaniel P. Berrangé
2616d92bdf4SRichard Henderson    ctx = g_new0(QCryptoCipherGcrypt, 1);
2621b010d93SRichard Henderson    ctx->base.driver = drv;
2636d92bdf4SRichard Henderson
2646d92bdf4SRichard Henderson    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
2656d92bdf4SRichard Henderson    if (err != 0) {
2666d92bdf4SRichard Henderson        error_setg(errp, "Cannot initialize cipher: %s",
2676d92bdf4SRichard Henderson                   gcry_strerror(err));
2686d92bdf4SRichard Henderson        goto error;
2696d92bdf4SRichard Henderson    }
2701b010d93SRichard Henderson    ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
2711b010d93SRichard Henderson
2726d92bdf4SRichard Henderson    err = gcry_cipher_setkey(ctx->handle, key, nkey);
2736d92bdf4SRichard Henderson    if (err != 0) {
2741b010d93SRichard Henderson        error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
2756d92bdf4SRichard Henderson        goto error;
2766d92bdf4SRichard Henderson    }
2776d92bdf4SRichard Henderson
2783eedf5ccSRichard Henderson    return &ctx->base;
2796d92bdf4SRichard Henderson
2806d92bdf4SRichard Henderson error:
2811b010d93SRichard Henderson    gcry_cipher_close(ctx->handle);
2821b010d93SRichard Henderson    g_free(ctx);
2836d92bdf4SRichard Henderson    return NULL;
2846d92bdf4SRichard Henderson}
285