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