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