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#ifdef CONFIG_QEMU_PRIVATE_XTS 226d92bdf4SRichard Henderson#include "crypto/xts.h" 236d92bdf4SRichard Henderson#endif 246d92bdf4SRichard Henderson 256d92bdf4SRichard Henderson#include <gcrypt.h> 266d92bdf4SRichard Henderson 276d92bdf4SRichard Henderson 286d92bdf4SRichard Hendersonbool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, 296d92bdf4SRichard Henderson QCryptoCipherMode mode) 306d92bdf4SRichard Henderson{ 316d92bdf4SRichard Henderson switch (alg) { 326d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_DES_RFB: 336d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 346d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 356d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 366d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 376d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 386d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 396d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 406d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 416d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 426d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 436d92bdf4SRichard Henderson break; 446d92bdf4SRichard Henderson default: 456d92bdf4SRichard Henderson return false; 466d92bdf4SRichard Henderson } 476d92bdf4SRichard Henderson 486d92bdf4SRichard Henderson switch (mode) { 496d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_ECB: 506d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CBC: 516d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_XTS: 526d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CTR: 536d92bdf4SRichard Henderson return true; 546d92bdf4SRichard Henderson default: 556d92bdf4SRichard Henderson return false; 566d92bdf4SRichard Henderson } 576d92bdf4SRichard Henderson} 586d92bdf4SRichard Henderson 596d92bdf4SRichard Hendersontypedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; 606d92bdf4SRichard Hendersonstruct QCryptoCipherGcrypt { 61*3eedf5ccSRichard Henderson QCryptoCipher base; 626d92bdf4SRichard Henderson gcry_cipher_hd_t handle; 636d92bdf4SRichard Henderson size_t blocksize; 646d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 656d92bdf4SRichard Henderson gcry_cipher_hd_t tweakhandle; 666d92bdf4SRichard Henderson /* Initialization vector or Counter */ 676d92bdf4SRichard Henderson uint8_t *iv; 686d92bdf4SRichard Henderson#endif 696d92bdf4SRichard Henderson}; 706d92bdf4SRichard Henderson 716d92bdf4SRichard Hendersonstatic void 726d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, 736d92bdf4SRichard Henderson QCryptoCipherMode mode) 746d92bdf4SRichard Henderson{ 756d92bdf4SRichard Henderson if (!ctx) { 766d92bdf4SRichard Henderson return; 776d92bdf4SRichard Henderson } 786d92bdf4SRichard Henderson 796d92bdf4SRichard Henderson gcry_cipher_close(ctx->handle); 806d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 816d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 826d92bdf4SRichard Henderson gcry_cipher_close(ctx->tweakhandle); 836d92bdf4SRichard Henderson } 846d92bdf4SRichard Henderson g_free(ctx->iv); 856d92bdf4SRichard Henderson#endif 866d92bdf4SRichard Henderson g_free(ctx); 876d92bdf4SRichard Henderson} 886d92bdf4SRichard Henderson 896d92bdf4SRichard Henderson 90*3eedf5ccSRichard Hendersonstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, 916d92bdf4SRichard Henderson QCryptoCipherMode mode, 926d92bdf4SRichard Henderson const uint8_t *key, 936d92bdf4SRichard Henderson size_t nkey, 946d92bdf4SRichard Henderson Error **errp) 956d92bdf4SRichard Henderson{ 966d92bdf4SRichard Henderson QCryptoCipherGcrypt *ctx; 976d92bdf4SRichard Henderson gcry_error_t err; 986d92bdf4SRichard Henderson int gcryalg, gcrymode; 996d92bdf4SRichard Henderson 1006d92bdf4SRichard Henderson switch (mode) { 1016d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_ECB: 1026d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_ECB; 1036d92bdf4SRichard Henderson break; 1046d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_XTS: 1056d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 1066d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_ECB; 1076d92bdf4SRichard Henderson#else 1086d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_XTS; 1096d92bdf4SRichard Henderson#endif 1106d92bdf4SRichard Henderson break; 1116d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CBC: 1126d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_CBC; 1136d92bdf4SRichard Henderson break; 1146d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CTR: 1156d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_CTR; 1166d92bdf4SRichard Henderson break; 1176d92bdf4SRichard Henderson default: 1186d92bdf4SRichard Henderson error_setg(errp, "Unsupported cipher mode %s", 1196d92bdf4SRichard Henderson QCryptoCipherMode_str(mode)); 1206d92bdf4SRichard Henderson return NULL; 1216d92bdf4SRichard Henderson } 1226d92bdf4SRichard Henderson 1236d92bdf4SRichard Henderson if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { 1246d92bdf4SRichard Henderson return NULL; 1256d92bdf4SRichard Henderson } 1266d92bdf4SRichard Henderson 1276d92bdf4SRichard Henderson switch (alg) { 1286d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_DES_RFB: 1296d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_DES; 1306d92bdf4SRichard Henderson break; 1316d92bdf4SRichard Henderson 1326d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 1336d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_3DES; 1346d92bdf4SRichard Henderson break; 1356d92bdf4SRichard Henderson 1366d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 1376d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES128; 1386d92bdf4SRichard Henderson break; 1396d92bdf4SRichard Henderson 1406d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 1416d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES192; 1426d92bdf4SRichard Henderson break; 1436d92bdf4SRichard Henderson 1446d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 1456d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES256; 1466d92bdf4SRichard Henderson break; 1476d92bdf4SRichard Henderson 1486d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 1496d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_CAST5; 1506d92bdf4SRichard Henderson break; 1516d92bdf4SRichard Henderson 1526d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 1536d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT128; 1546d92bdf4SRichard Henderson break; 1556d92bdf4SRichard Henderson 1566d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 1576d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT192; 1586d92bdf4SRichard Henderson break; 1596d92bdf4SRichard Henderson 1606d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 1616d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT256; 1626d92bdf4SRichard Henderson break; 1636d92bdf4SRichard Henderson 1646d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 1656d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_TWOFISH128; 1666d92bdf4SRichard Henderson break; 1676d92bdf4SRichard Henderson 1686d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 1696d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_TWOFISH; 1706d92bdf4SRichard Henderson break; 1716d92bdf4SRichard Henderson 1726d92bdf4SRichard Henderson default: 1736d92bdf4SRichard Henderson error_setg(errp, "Unsupported cipher algorithm %s", 1746d92bdf4SRichard Henderson QCryptoCipherAlgorithm_str(alg)); 1756d92bdf4SRichard Henderson return NULL; 1766d92bdf4SRichard Henderson } 1776d92bdf4SRichard Henderson 1786d92bdf4SRichard Henderson ctx = g_new0(QCryptoCipherGcrypt, 1); 1796d92bdf4SRichard Henderson 1806d92bdf4SRichard Henderson err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); 1816d92bdf4SRichard Henderson if (err != 0) { 1826d92bdf4SRichard Henderson error_setg(errp, "Cannot initialize cipher: %s", 1836d92bdf4SRichard Henderson gcry_strerror(err)); 1846d92bdf4SRichard Henderson goto error; 1856d92bdf4SRichard Henderson } 1866d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 1876d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 1886d92bdf4SRichard Henderson err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); 1896d92bdf4SRichard Henderson if (err != 0) { 1906d92bdf4SRichard Henderson error_setg(errp, "Cannot initialize cipher: %s", 1916d92bdf4SRichard Henderson gcry_strerror(err)); 1926d92bdf4SRichard Henderson goto error; 1936d92bdf4SRichard Henderson } 1946d92bdf4SRichard Henderson } 1956d92bdf4SRichard Henderson#endif 1966d92bdf4SRichard Henderson 1976d92bdf4SRichard Henderson if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { 1986d92bdf4SRichard Henderson /* We're using standard DES cipher from gcrypt, so we need 1996d92bdf4SRichard Henderson * to munge the key so that the results are the same as the 2006d92bdf4SRichard Henderson * bizarre RFB variant of DES :-) 2016d92bdf4SRichard Henderson */ 2026d92bdf4SRichard Henderson uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); 2036d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); 2046d92bdf4SRichard Henderson g_free(rfbkey); 2056d92bdf4SRichard Henderson ctx->blocksize = 8; 2066d92bdf4SRichard Henderson } else { 2076d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 2086d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 2096d92bdf4SRichard Henderson nkey /= 2; 2106d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, key, nkey); 2116d92bdf4SRichard Henderson if (err != 0) { 2126d92bdf4SRichard Henderson error_setg(errp, "Cannot set key: %s", 2136d92bdf4SRichard Henderson gcry_strerror(err)); 2146d92bdf4SRichard Henderson goto error; 2156d92bdf4SRichard Henderson } 2166d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); 2176d92bdf4SRichard Henderson } else { 2186d92bdf4SRichard Henderson#endif 2196d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, key, nkey); 2206d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 2216d92bdf4SRichard Henderson } 2226d92bdf4SRichard Henderson#endif 2236d92bdf4SRichard Henderson if (err != 0) { 2246d92bdf4SRichard Henderson error_setg(errp, "Cannot set key: %s", 2256d92bdf4SRichard Henderson gcry_strerror(err)); 2266d92bdf4SRichard Henderson goto error; 2276d92bdf4SRichard Henderson } 2286d92bdf4SRichard Henderson switch (alg) { 2296d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 2306d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 2316d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 2326d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 2336d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 2346d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 2356d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 2366d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 2376d92bdf4SRichard Henderson ctx->blocksize = 16; 2386d92bdf4SRichard Henderson break; 2396d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 2406d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 2416d92bdf4SRichard Henderson ctx->blocksize = 8; 2426d92bdf4SRichard Henderson break; 2436d92bdf4SRichard Henderson default: 2446d92bdf4SRichard Henderson g_assert_not_reached(); 2456d92bdf4SRichard Henderson } 2466d92bdf4SRichard Henderson } 2476d92bdf4SRichard Henderson g_assert(is_power_of_2(ctx->blocksize)); 2486d92bdf4SRichard Henderson 2496d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 2506d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 2516d92bdf4SRichard Henderson if (ctx->blocksize != XTS_BLOCK_SIZE) { 2526d92bdf4SRichard Henderson error_setg(errp, 2536d92bdf4SRichard Henderson "Cipher block size %zu must equal XTS block size %d", 2546d92bdf4SRichard Henderson ctx->blocksize, XTS_BLOCK_SIZE); 2556d92bdf4SRichard Henderson goto error; 2566d92bdf4SRichard Henderson } 2576d92bdf4SRichard Henderson ctx->iv = g_new0(uint8_t, ctx->blocksize); 2586d92bdf4SRichard Henderson } 2596d92bdf4SRichard Henderson#endif 2606d92bdf4SRichard Henderson 261*3eedf5ccSRichard Henderson return &ctx->base; 2626d92bdf4SRichard Henderson 2636d92bdf4SRichard Henderson error: 2646d92bdf4SRichard Henderson qcrypto_gcrypt_cipher_free_ctx(ctx, mode); 2656d92bdf4SRichard Henderson return NULL; 2666d92bdf4SRichard Henderson} 2676d92bdf4SRichard Henderson 2686d92bdf4SRichard Henderson 2696d92bdf4SRichard Hendersonstatic void 2706d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) 2716d92bdf4SRichard Henderson{ 272*3eedf5ccSRichard Henderson QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); 273*3eedf5ccSRichard Henderson 274*3eedf5ccSRichard Henderson qcrypto_gcrypt_cipher_free_ctx(ctx, cipher->mode); 2756d92bdf4SRichard Henderson} 2766d92bdf4SRichard Henderson 2776d92bdf4SRichard Henderson 2786d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 2796d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_encrypt(const void *ctx, 2806d92bdf4SRichard Henderson size_t length, 2816d92bdf4SRichard Henderson uint8_t *dst, 2826d92bdf4SRichard Henderson const uint8_t *src) 2836d92bdf4SRichard Henderson{ 2846d92bdf4SRichard Henderson gcry_error_t err; 2856d92bdf4SRichard Henderson err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 2866d92bdf4SRichard Henderson g_assert(err == 0); 2876d92bdf4SRichard Henderson} 2886d92bdf4SRichard Henderson 2896d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_decrypt(const void *ctx, 2906d92bdf4SRichard Henderson size_t length, 2916d92bdf4SRichard Henderson uint8_t *dst, 2926d92bdf4SRichard Henderson const uint8_t *src) 2936d92bdf4SRichard Henderson{ 2946d92bdf4SRichard Henderson gcry_error_t err; 2956d92bdf4SRichard Henderson err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 2966d92bdf4SRichard Henderson g_assert(err == 0); 2976d92bdf4SRichard Henderson} 2986d92bdf4SRichard Henderson#endif 2996d92bdf4SRichard Henderson 3006d92bdf4SRichard Hendersonstatic int 3016d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, 3026d92bdf4SRichard Henderson const void *in, 3036d92bdf4SRichard Henderson void *out, 3046d92bdf4SRichard Henderson size_t len, 3056d92bdf4SRichard Henderson Error **errp) 3066d92bdf4SRichard Henderson{ 307*3eedf5ccSRichard Henderson QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); 3086d92bdf4SRichard Henderson gcry_error_t err; 3096d92bdf4SRichard Henderson 3106d92bdf4SRichard Henderson if (len & (ctx->blocksize - 1)) { 3116d92bdf4SRichard Henderson error_setg(errp, "Length %zu must be a multiple of block size %zu", 3126d92bdf4SRichard Henderson len, ctx->blocksize); 3136d92bdf4SRichard Henderson return -1; 3146d92bdf4SRichard Henderson } 3156d92bdf4SRichard Henderson 3166d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 3176d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 3186d92bdf4SRichard Henderson xts_encrypt(ctx->handle, ctx->tweakhandle, 3196d92bdf4SRichard Henderson qcrypto_gcrypt_xts_encrypt, 3206d92bdf4SRichard Henderson qcrypto_gcrypt_xts_decrypt, 3216d92bdf4SRichard Henderson ctx->iv, len, out, in); 3226d92bdf4SRichard Henderson return 0; 3236d92bdf4SRichard Henderson } 3246d92bdf4SRichard Henderson#endif 3256d92bdf4SRichard Henderson 3266d92bdf4SRichard Henderson err = gcry_cipher_encrypt(ctx->handle, 3276d92bdf4SRichard Henderson out, len, 3286d92bdf4SRichard Henderson in, len); 3296d92bdf4SRichard Henderson if (err != 0) { 3306d92bdf4SRichard Henderson error_setg(errp, "Cannot encrypt data: %s", 3316d92bdf4SRichard Henderson gcry_strerror(err)); 3326d92bdf4SRichard Henderson return -1; 3336d92bdf4SRichard Henderson } 3346d92bdf4SRichard Henderson 3356d92bdf4SRichard Henderson return 0; 3366d92bdf4SRichard Henderson} 3376d92bdf4SRichard Henderson 3386d92bdf4SRichard Henderson 3396d92bdf4SRichard Hendersonstatic int 3406d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, 3416d92bdf4SRichard Henderson const void *in, 3426d92bdf4SRichard Henderson void *out, 3436d92bdf4SRichard Henderson size_t len, 3446d92bdf4SRichard Henderson Error **errp) 3456d92bdf4SRichard Henderson{ 346*3eedf5ccSRichard Henderson QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); 3476d92bdf4SRichard Henderson gcry_error_t err; 3486d92bdf4SRichard Henderson 3496d92bdf4SRichard Henderson if (len & (ctx->blocksize - 1)) { 3506d92bdf4SRichard Henderson error_setg(errp, "Length %zu must be a multiple of block size %zu", 3516d92bdf4SRichard Henderson len, ctx->blocksize); 3526d92bdf4SRichard Henderson return -1; 3536d92bdf4SRichard Henderson } 3546d92bdf4SRichard Henderson 3556d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 3566d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 3576d92bdf4SRichard Henderson xts_decrypt(ctx->handle, ctx->tweakhandle, 3586d92bdf4SRichard Henderson qcrypto_gcrypt_xts_encrypt, 3596d92bdf4SRichard Henderson qcrypto_gcrypt_xts_decrypt, 3606d92bdf4SRichard Henderson ctx->iv, len, out, in); 3616d92bdf4SRichard Henderson return 0; 3626d92bdf4SRichard Henderson } 3636d92bdf4SRichard Henderson#endif 3646d92bdf4SRichard Henderson 3656d92bdf4SRichard Henderson err = gcry_cipher_decrypt(ctx->handle, 3666d92bdf4SRichard Henderson out, len, 3676d92bdf4SRichard Henderson in, len); 3686d92bdf4SRichard Henderson if (err != 0) { 3696d92bdf4SRichard Henderson error_setg(errp, "Cannot decrypt data: %s", 3706d92bdf4SRichard Henderson gcry_strerror(err)); 3716d92bdf4SRichard Henderson return -1; 3726d92bdf4SRichard Henderson } 3736d92bdf4SRichard Henderson 3746d92bdf4SRichard Henderson return 0; 3756d92bdf4SRichard Henderson} 3766d92bdf4SRichard Henderson 3776d92bdf4SRichard Hendersonstatic int 3786d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, 3796d92bdf4SRichard Henderson const uint8_t *iv, size_t niv, 3806d92bdf4SRichard Henderson Error **errp) 3816d92bdf4SRichard Henderson{ 382*3eedf5ccSRichard Henderson QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); 3836d92bdf4SRichard Henderson gcry_error_t err; 3846d92bdf4SRichard Henderson 3856d92bdf4SRichard Henderson if (niv != ctx->blocksize) { 3866d92bdf4SRichard Henderson error_setg(errp, "Expected IV size %zu not %zu", 3876d92bdf4SRichard Henderson ctx->blocksize, niv); 3886d92bdf4SRichard Henderson return -1; 3896d92bdf4SRichard Henderson } 3906d92bdf4SRichard Henderson 3916d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 3926d92bdf4SRichard Henderson if (ctx->iv) { 3936d92bdf4SRichard Henderson memcpy(ctx->iv, iv, niv); 3946d92bdf4SRichard Henderson return 0; 3956d92bdf4SRichard Henderson } 3966d92bdf4SRichard Henderson#endif 3976d92bdf4SRichard Henderson 3986d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { 3996d92bdf4SRichard Henderson err = gcry_cipher_setctr(ctx->handle, iv, niv); 4006d92bdf4SRichard Henderson if (err != 0) { 4016d92bdf4SRichard Henderson error_setg(errp, "Cannot set Counter: %s", 4026d92bdf4SRichard Henderson gcry_strerror(err)); 4036d92bdf4SRichard Henderson return -1; 4046d92bdf4SRichard Henderson } 4056d92bdf4SRichard Henderson } else { 4066d92bdf4SRichard Henderson gcry_cipher_reset(ctx->handle); 4076d92bdf4SRichard Henderson err = gcry_cipher_setiv(ctx->handle, iv, niv); 4086d92bdf4SRichard Henderson if (err != 0) { 4096d92bdf4SRichard Henderson error_setg(errp, "Cannot set IV: %s", 4106d92bdf4SRichard Henderson gcry_strerror(err)); 4116d92bdf4SRichard Henderson return -1; 4126d92bdf4SRichard Henderson } 4136d92bdf4SRichard Henderson } 4146d92bdf4SRichard Henderson 4156d92bdf4SRichard Henderson return 0; 4166d92bdf4SRichard Henderson} 4176d92bdf4SRichard Henderson 4186d92bdf4SRichard Henderson 4197b5dbfb7SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { 4206d92bdf4SRichard Henderson .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt, 4216d92bdf4SRichard Henderson .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt, 4226d92bdf4SRichard Henderson .cipher_setiv = qcrypto_gcrypt_cipher_setiv, 4236d92bdf4SRichard Henderson .cipher_free = qcrypto_gcrypt_cipher_ctx_free, 4246d92bdf4SRichard Henderson}; 425