xref: /openbmc/qemu/crypto/cipher-gcrypt.c.inc (revision 52ed9f455ee0063958a1b18e54cab9a427fc422f)
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
236d92bdf4SRichard Hendersonbool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
246d92bdf4SRichard Henderson                             QCryptoCipherMode mode)
256d92bdf4SRichard Henderson{
266d92bdf4SRichard Henderson    switch (alg) {
2783bee4b5SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_DES:
286d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_3DES:
296d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_128:
306d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_192:
316d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_256:
326d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_CAST5_128:
336d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_128:
346d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_192:
356d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_256:
366d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
376d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
38*52ed9f45SHyman Huang#ifdef CONFIG_CRYPTO_SM4
39*52ed9f45SHyman Huang    case QCRYPTO_CIPHER_ALG_SM4:
40*52ed9f45SHyman Huang#endif
416d92bdf4SRichard Henderson        break;
426d92bdf4SRichard Henderson    default:
436d92bdf4SRichard Henderson        return false;
446d92bdf4SRichard Henderson    }
456d92bdf4SRichard Henderson
466d92bdf4SRichard Henderson    switch (mode) {
476d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
486d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
496d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
506d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
516d92bdf4SRichard Henderson        return true;
526d92bdf4SRichard Henderson    default:
536d92bdf4SRichard Henderson        return false;
546d92bdf4SRichard Henderson    }
556d92bdf4SRichard Henderson}
566d92bdf4SRichard Henderson
571b010d93SRichard Hendersontypedef struct QCryptoCipherGcrypt {
583eedf5ccSRichard Henderson    QCryptoCipher base;
596d92bdf4SRichard Henderson    gcry_cipher_hd_t handle;
606d92bdf4SRichard Henderson    size_t blocksize;
611b010d93SRichard Henderson} QCryptoCipherGcrypt;
626d92bdf4SRichard Henderson
631b010d93SRichard Henderson
641b010d93SRichard Hendersonstatic void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
656d92bdf4SRichard Henderson{
661b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
676d92bdf4SRichard Henderson
686d92bdf4SRichard Henderson    gcry_cipher_close(ctx->handle);
696d92bdf4SRichard Henderson    g_free(ctx);
706d92bdf4SRichard Henderson}
716d92bdf4SRichard Henderson
721b010d93SRichard Hendersonstatic int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
731b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
741b010d93SRichard Henderson{
751b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
761b010d93SRichard Henderson    gcry_error_t err;
771b010d93SRichard Henderson
781b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
791b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
801b010d93SRichard Henderson                   len, ctx->blocksize);
811b010d93SRichard Henderson        return -1;
821b010d93SRichard Henderson    }
831b010d93SRichard Henderson
841b010d93SRichard Henderson    err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
851b010d93SRichard Henderson    if (err != 0) {
861b010d93SRichard Henderson        error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
871b010d93SRichard Henderson        return -1;
881b010d93SRichard Henderson    }
891b010d93SRichard Henderson
901b010d93SRichard Henderson    return 0;
911b010d93SRichard Henderson}
921b010d93SRichard Henderson
931b010d93SRichard Henderson
941b010d93SRichard Hendersonstatic int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
951b010d93SRichard Henderson                                  void *out, size_t len, Error **errp)
961b010d93SRichard Henderson{
971b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
981b010d93SRichard Henderson    gcry_error_t err;
991b010d93SRichard Henderson
1001b010d93SRichard Henderson    if (len & (ctx->blocksize - 1)) {
1011b010d93SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
1021b010d93SRichard Henderson                   len, ctx->blocksize);
1031b010d93SRichard Henderson        return -1;
1041b010d93SRichard Henderson    }
1051b010d93SRichard Henderson
1061b010d93SRichard Henderson    err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
1071b010d93SRichard Henderson    if (err != 0) {
1081b010d93SRichard Henderson        error_setg(errp, "Cannot decrypt data: %s",
1091b010d93SRichard Henderson                   gcry_strerror(err));
1101b010d93SRichard Henderson        return -1;
1111b010d93SRichard Henderson    }
1121b010d93SRichard Henderson
1131b010d93SRichard Henderson    return 0;
1141b010d93SRichard Henderson}
1151b010d93SRichard Henderson
1161b010d93SRichard Hendersonstatic int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
1171b010d93SRichard Henderson                                const uint8_t *iv, size_t niv,
1181b010d93SRichard Henderson                                Error **errp)
1191b010d93SRichard Henderson{
1201b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1211b010d93SRichard Henderson    gcry_error_t err;
1221b010d93SRichard Henderson
1231b010d93SRichard Henderson    if (niv != ctx->blocksize) {
1241b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
1251b010d93SRichard Henderson                   ctx->blocksize, niv);
1261b010d93SRichard Henderson        return -1;
1271b010d93SRichard Henderson    }
1281b010d93SRichard Henderson
1291b010d93SRichard Henderson    gcry_cipher_reset(ctx->handle);
1301b010d93SRichard Henderson    err = gcry_cipher_setiv(ctx->handle, iv, niv);
1311b010d93SRichard Henderson    if (err != 0) {
1321b010d93SRichard Henderson        error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
1331b010d93SRichard Henderson        return -1;
1341b010d93SRichard Henderson    }
1351b010d93SRichard Henderson
1361b010d93SRichard Henderson    return 0;
1371b010d93SRichard Henderson}
1381b010d93SRichard Henderson
1391b010d93SRichard Hendersonstatic int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
1401b010d93SRichard Henderson                                    const uint8_t *iv, size_t niv,
1411b010d93SRichard Henderson                                    Error **errp)
1421b010d93SRichard Henderson{
1431b010d93SRichard Henderson    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
1441b010d93SRichard Henderson    gcry_error_t err;
1451b010d93SRichard Henderson
1461b010d93SRichard Henderson    if (niv != ctx->blocksize) {
1471b010d93SRichard Henderson        error_setg(errp, "Expected IV size %zu not %zu",
1481b010d93SRichard Henderson                   ctx->blocksize, niv);
1491b010d93SRichard Henderson        return -1;
1501b010d93SRichard Henderson    }
1511b010d93SRichard Henderson
1521b010d93SRichard Henderson    err = gcry_cipher_setctr(ctx->handle, iv, niv);
1531b010d93SRichard Henderson    if (err != 0) {
1541b010d93SRichard Henderson        error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
1551b010d93SRichard Henderson        return -1;
1561b010d93SRichard Henderson    }
1571b010d93SRichard Henderson
1581b010d93SRichard Henderson    return 0;
1591b010d93SRichard Henderson}
1601b010d93SRichard Henderson
1611b010d93SRichard Henderson
1621b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
1631b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
1641b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
1651b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_setiv,
1661b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
1671b010d93SRichard Henderson};
1681b010d93SRichard Henderson
1691b010d93SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
1701b010d93SRichard Henderson    .cipher_encrypt = qcrypto_gcrypt_encrypt,
1711b010d93SRichard Henderson    .cipher_decrypt = qcrypto_gcrypt_decrypt,
1721b010d93SRichard Henderson    .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
1731b010d93SRichard Henderson    .cipher_free = qcrypto_gcrypt_ctx_free,
1741b010d93SRichard Henderson};
1751b010d93SRichard Henderson
1763eedf5ccSRichard Hendersonstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
1776d92bdf4SRichard Henderson                                             QCryptoCipherMode mode,
1786d92bdf4SRichard Henderson                                             const uint8_t *key,
1796d92bdf4SRichard Henderson                                             size_t nkey,
1806d92bdf4SRichard Henderson                                             Error **errp)
1816d92bdf4SRichard Henderson{
1826d92bdf4SRichard Henderson    QCryptoCipherGcrypt *ctx;
1831b010d93SRichard Henderson    const QCryptoCipherDriver *drv;
1846d92bdf4SRichard Henderson    gcry_error_t err;
1856d92bdf4SRichard Henderson    int gcryalg, gcrymode;
1866d92bdf4SRichard Henderson
1876d92bdf4SRichard Henderson    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
1886d92bdf4SRichard Henderson        return NULL;
1896d92bdf4SRichard Henderson    }
1906d92bdf4SRichard Henderson
1916d92bdf4SRichard Henderson    switch (alg) {
19283bee4b5SDaniel P. Berrangé    case QCRYPTO_CIPHER_ALG_DES:
1936d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_DES;
1946d92bdf4SRichard Henderson        break;
1956d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_3DES:
1966d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_3DES;
1976d92bdf4SRichard Henderson        break;
1986d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_128:
1996d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES128;
2006d92bdf4SRichard Henderson        break;
2016d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_192:
2026d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES192;
2036d92bdf4SRichard Henderson        break;
2046d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_AES_256:
2056d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_AES256;
2066d92bdf4SRichard Henderson        break;
2076d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_CAST5_128:
2086d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_CAST5;
2096d92bdf4SRichard Henderson        break;
2106d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_128:
2116d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT128;
2126d92bdf4SRichard Henderson        break;
2136d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_192:
2146d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT192;
2156d92bdf4SRichard Henderson        break;
2166d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_SERPENT_256:
2176d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_SERPENT256;
2186d92bdf4SRichard Henderson        break;
2196d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
2206d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_TWOFISH128;
2216d92bdf4SRichard Henderson        break;
2226d92bdf4SRichard Henderson    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
2236d92bdf4SRichard Henderson        gcryalg = GCRY_CIPHER_TWOFISH;
2246d92bdf4SRichard Henderson        break;
225*52ed9f45SHyman Huang#ifdef CONFIG_CRYPTO_SM4
226*52ed9f45SHyman Huang    case QCRYPTO_CIPHER_ALG_SM4:
227*52ed9f45SHyman Huang        gcryalg = GCRY_CIPHER_SM4;
228*52ed9f45SHyman Huang        break;
229*52ed9f45SHyman Huang#endif
2306d92bdf4SRichard Henderson    default:
2316d92bdf4SRichard Henderson        error_setg(errp, "Unsupported cipher algorithm %s",
2326d92bdf4SRichard Henderson                   QCryptoCipherAlgorithm_str(alg));
2336d92bdf4SRichard Henderson        return NULL;
2346d92bdf4SRichard Henderson    }
2356d92bdf4SRichard Henderson
2361b010d93SRichard Henderson    drv = &qcrypto_gcrypt_driver;
2371b010d93SRichard Henderson    switch (mode) {
2381b010d93SRichard Henderson    case QCRYPTO_CIPHER_MODE_ECB:
2391b010d93SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_ECB;
2401b010d93SRichard Henderson        break;
2411b010d93SRichard Henderson    case QCRYPTO_CIPHER_MODE_XTS:
2421b010d93SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_XTS;
2431b010d93SRichard Henderson        break;
2441b010d93SRichard Henderson    case QCRYPTO_CIPHER_MODE_CBC:
2451b010d93SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_CBC;
2461b010d93SRichard Henderson        break;
2471b010d93SRichard Henderson    case QCRYPTO_CIPHER_MODE_CTR:
2481b010d93SRichard Henderson        drv = &qcrypto_gcrypt_ctr_driver;
2491b010d93SRichard Henderson        gcrymode = GCRY_CIPHER_MODE_CTR;
2501b010d93SRichard Henderson        break;
2511b010d93SRichard Henderson    default:
2521b010d93SRichard Henderson        error_setg(errp, "Unsupported cipher mode %s",
2531b010d93SRichard Henderson                   QCryptoCipherMode_str(mode));
2541b010d93SRichard Henderson        return NULL;
2551b010d93SRichard Henderson    }
2561b010d93SRichard Henderson
2576d92bdf4SRichard Henderson    ctx = g_new0(QCryptoCipherGcrypt, 1);
2581b010d93SRichard Henderson    ctx->base.driver = drv;
2596d92bdf4SRichard Henderson
2606d92bdf4SRichard Henderson    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
2616d92bdf4SRichard Henderson    if (err != 0) {
2626d92bdf4SRichard Henderson        error_setg(errp, "Cannot initialize cipher: %s",
2636d92bdf4SRichard Henderson                   gcry_strerror(err));
2646d92bdf4SRichard Henderson        goto error;
2656d92bdf4SRichard Henderson    }
2661b010d93SRichard Henderson    ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
2671b010d93SRichard Henderson
2686d92bdf4SRichard Henderson    err = gcry_cipher_setkey(ctx->handle, key, nkey);
2696d92bdf4SRichard Henderson    if (err != 0) {
2701b010d93SRichard Henderson        error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
2716d92bdf4SRichard Henderson        goto error;
2726d92bdf4SRichard Henderson    }
2736d92bdf4SRichard Henderson
2743eedf5ccSRichard Henderson    return &ctx->base;
2756d92bdf4SRichard Henderson
2766d92bdf4SRichard Henderson error:
2771b010d93SRichard Henderson    gcry_cipher_close(ctx->handle);
2781b010d93SRichard Henderson    g_free(ctx);
2796d92bdf4SRichard Henderson    return NULL;
2806d92bdf4SRichard Henderson}
281