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