1*6d92bdf4SRichard Henderson/* 2*6d92bdf4SRichard Henderson * QEMU Crypto cipher libgcrypt algorithms 3*6d92bdf4SRichard Henderson * 4*6d92bdf4SRichard Henderson * Copyright (c) 2015 Red Hat, Inc. 5*6d92bdf4SRichard Henderson * 6*6d92bdf4SRichard Henderson * This library is free software; you can redistribute it and/or 7*6d92bdf4SRichard Henderson * modify it under the terms of the GNU Lesser General Public 8*6d92bdf4SRichard Henderson * License as published by the Free Software Foundation; either 9*6d92bdf4SRichard Henderson * version 2.1 of the License, or (at your option) any later version. 10*6d92bdf4SRichard Henderson * 11*6d92bdf4SRichard Henderson * This library is distributed in the hope that it will be useful, 12*6d92bdf4SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*6d92bdf4SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*6d92bdf4SRichard Henderson * Lesser General Public License for more details. 15*6d92bdf4SRichard Henderson * 16*6d92bdf4SRichard Henderson * You should have received a copy of the GNU Lesser General Public 17*6d92bdf4SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*6d92bdf4SRichard Henderson * 19*6d92bdf4SRichard Henderson */ 20*6d92bdf4SRichard Henderson 21*6d92bdf4SRichard Henderson#include "qemu/osdep.h" 22*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 23*6d92bdf4SRichard Henderson#include "crypto/xts.h" 24*6d92bdf4SRichard Henderson#endif 25*6d92bdf4SRichard Henderson#include "cipherpriv.h" 26*6d92bdf4SRichard Henderson 27*6d92bdf4SRichard Henderson#include <gcrypt.h> 28*6d92bdf4SRichard Henderson 29*6d92bdf4SRichard Henderson 30*6d92bdf4SRichard Hendersonbool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, 31*6d92bdf4SRichard Henderson QCryptoCipherMode mode) 32*6d92bdf4SRichard Henderson{ 33*6d92bdf4SRichard Henderson switch (alg) { 34*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_DES_RFB: 35*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 36*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 37*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 38*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 39*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 40*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 41*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 42*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 43*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 44*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 45*6d92bdf4SRichard Henderson break; 46*6d92bdf4SRichard Henderson default: 47*6d92bdf4SRichard Henderson return false; 48*6d92bdf4SRichard Henderson } 49*6d92bdf4SRichard Henderson 50*6d92bdf4SRichard Henderson switch (mode) { 51*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_ECB: 52*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CBC: 53*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_XTS: 54*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CTR: 55*6d92bdf4SRichard Henderson return true; 56*6d92bdf4SRichard Henderson default: 57*6d92bdf4SRichard Henderson return false; 58*6d92bdf4SRichard Henderson } 59*6d92bdf4SRichard Henderson} 60*6d92bdf4SRichard Henderson 61*6d92bdf4SRichard Hendersontypedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; 62*6d92bdf4SRichard Hendersonstruct QCryptoCipherGcrypt { 63*6d92bdf4SRichard Henderson gcry_cipher_hd_t handle; 64*6d92bdf4SRichard Henderson size_t blocksize; 65*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 66*6d92bdf4SRichard Henderson gcry_cipher_hd_t tweakhandle; 67*6d92bdf4SRichard Henderson /* Initialization vector or Counter */ 68*6d92bdf4SRichard Henderson uint8_t *iv; 69*6d92bdf4SRichard Henderson#endif 70*6d92bdf4SRichard Henderson}; 71*6d92bdf4SRichard Henderson 72*6d92bdf4SRichard Hendersonstatic void 73*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, 74*6d92bdf4SRichard Henderson QCryptoCipherMode mode) 75*6d92bdf4SRichard Henderson{ 76*6d92bdf4SRichard Henderson if (!ctx) { 77*6d92bdf4SRichard Henderson return; 78*6d92bdf4SRichard Henderson } 79*6d92bdf4SRichard Henderson 80*6d92bdf4SRichard Henderson gcry_cipher_close(ctx->handle); 81*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 82*6d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 83*6d92bdf4SRichard Henderson gcry_cipher_close(ctx->tweakhandle); 84*6d92bdf4SRichard Henderson } 85*6d92bdf4SRichard Henderson g_free(ctx->iv); 86*6d92bdf4SRichard Henderson#endif 87*6d92bdf4SRichard Henderson g_free(ctx); 88*6d92bdf4SRichard Henderson} 89*6d92bdf4SRichard Henderson 90*6d92bdf4SRichard Henderson 91*6d92bdf4SRichard Hendersonstatic QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, 92*6d92bdf4SRichard Henderson QCryptoCipherMode mode, 93*6d92bdf4SRichard Henderson const uint8_t *key, 94*6d92bdf4SRichard Henderson size_t nkey, 95*6d92bdf4SRichard Henderson Error **errp) 96*6d92bdf4SRichard Henderson{ 97*6d92bdf4SRichard Henderson QCryptoCipherGcrypt *ctx; 98*6d92bdf4SRichard Henderson gcry_error_t err; 99*6d92bdf4SRichard Henderson int gcryalg, gcrymode; 100*6d92bdf4SRichard Henderson 101*6d92bdf4SRichard Henderson switch (mode) { 102*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_ECB: 103*6d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_ECB; 104*6d92bdf4SRichard Henderson break; 105*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_XTS: 106*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 107*6d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_ECB; 108*6d92bdf4SRichard Henderson#else 109*6d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_XTS; 110*6d92bdf4SRichard Henderson#endif 111*6d92bdf4SRichard Henderson break; 112*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CBC: 113*6d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_CBC; 114*6d92bdf4SRichard Henderson break; 115*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_MODE_CTR: 116*6d92bdf4SRichard Henderson gcrymode = GCRY_CIPHER_MODE_CTR; 117*6d92bdf4SRichard Henderson break; 118*6d92bdf4SRichard Henderson default: 119*6d92bdf4SRichard Henderson error_setg(errp, "Unsupported cipher mode %s", 120*6d92bdf4SRichard Henderson QCryptoCipherMode_str(mode)); 121*6d92bdf4SRichard Henderson return NULL; 122*6d92bdf4SRichard Henderson } 123*6d92bdf4SRichard Henderson 124*6d92bdf4SRichard Henderson if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { 125*6d92bdf4SRichard Henderson return NULL; 126*6d92bdf4SRichard Henderson } 127*6d92bdf4SRichard Henderson 128*6d92bdf4SRichard Henderson switch (alg) { 129*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_DES_RFB: 130*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_DES; 131*6d92bdf4SRichard Henderson break; 132*6d92bdf4SRichard Henderson 133*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 134*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_3DES; 135*6d92bdf4SRichard Henderson break; 136*6d92bdf4SRichard Henderson 137*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 138*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES128; 139*6d92bdf4SRichard Henderson break; 140*6d92bdf4SRichard Henderson 141*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 142*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES192; 143*6d92bdf4SRichard Henderson break; 144*6d92bdf4SRichard Henderson 145*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 146*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_AES256; 147*6d92bdf4SRichard Henderson break; 148*6d92bdf4SRichard Henderson 149*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 150*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_CAST5; 151*6d92bdf4SRichard Henderson break; 152*6d92bdf4SRichard Henderson 153*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 154*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT128; 155*6d92bdf4SRichard Henderson break; 156*6d92bdf4SRichard Henderson 157*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 158*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT192; 159*6d92bdf4SRichard Henderson break; 160*6d92bdf4SRichard Henderson 161*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 162*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_SERPENT256; 163*6d92bdf4SRichard Henderson break; 164*6d92bdf4SRichard Henderson 165*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 166*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_TWOFISH128; 167*6d92bdf4SRichard Henderson break; 168*6d92bdf4SRichard Henderson 169*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 170*6d92bdf4SRichard Henderson gcryalg = GCRY_CIPHER_TWOFISH; 171*6d92bdf4SRichard Henderson break; 172*6d92bdf4SRichard Henderson 173*6d92bdf4SRichard Henderson default: 174*6d92bdf4SRichard Henderson error_setg(errp, "Unsupported cipher algorithm %s", 175*6d92bdf4SRichard Henderson QCryptoCipherAlgorithm_str(alg)); 176*6d92bdf4SRichard Henderson return NULL; 177*6d92bdf4SRichard Henderson } 178*6d92bdf4SRichard Henderson 179*6d92bdf4SRichard Henderson ctx = g_new0(QCryptoCipherGcrypt, 1); 180*6d92bdf4SRichard Henderson 181*6d92bdf4SRichard Henderson err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); 182*6d92bdf4SRichard Henderson if (err != 0) { 183*6d92bdf4SRichard Henderson error_setg(errp, "Cannot initialize cipher: %s", 184*6d92bdf4SRichard Henderson gcry_strerror(err)); 185*6d92bdf4SRichard Henderson goto error; 186*6d92bdf4SRichard Henderson } 187*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 188*6d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 189*6d92bdf4SRichard Henderson err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); 190*6d92bdf4SRichard Henderson if (err != 0) { 191*6d92bdf4SRichard Henderson error_setg(errp, "Cannot initialize cipher: %s", 192*6d92bdf4SRichard Henderson gcry_strerror(err)); 193*6d92bdf4SRichard Henderson goto error; 194*6d92bdf4SRichard Henderson } 195*6d92bdf4SRichard Henderson } 196*6d92bdf4SRichard Henderson#endif 197*6d92bdf4SRichard Henderson 198*6d92bdf4SRichard Henderson if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { 199*6d92bdf4SRichard Henderson /* We're using standard DES cipher from gcrypt, so we need 200*6d92bdf4SRichard Henderson * to munge the key so that the results are the same as the 201*6d92bdf4SRichard Henderson * bizarre RFB variant of DES :-) 202*6d92bdf4SRichard Henderson */ 203*6d92bdf4SRichard Henderson uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); 204*6d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); 205*6d92bdf4SRichard Henderson g_free(rfbkey); 206*6d92bdf4SRichard Henderson ctx->blocksize = 8; 207*6d92bdf4SRichard Henderson } else { 208*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 209*6d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 210*6d92bdf4SRichard Henderson nkey /= 2; 211*6d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, key, nkey); 212*6d92bdf4SRichard Henderson if (err != 0) { 213*6d92bdf4SRichard Henderson error_setg(errp, "Cannot set key: %s", 214*6d92bdf4SRichard Henderson gcry_strerror(err)); 215*6d92bdf4SRichard Henderson goto error; 216*6d92bdf4SRichard Henderson } 217*6d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); 218*6d92bdf4SRichard Henderson } else { 219*6d92bdf4SRichard Henderson#endif 220*6d92bdf4SRichard Henderson err = gcry_cipher_setkey(ctx->handle, key, nkey); 221*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 222*6d92bdf4SRichard Henderson } 223*6d92bdf4SRichard Henderson#endif 224*6d92bdf4SRichard Henderson if (err != 0) { 225*6d92bdf4SRichard Henderson error_setg(errp, "Cannot set key: %s", 226*6d92bdf4SRichard Henderson gcry_strerror(err)); 227*6d92bdf4SRichard Henderson goto error; 228*6d92bdf4SRichard Henderson } 229*6d92bdf4SRichard Henderson switch (alg) { 230*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_128: 231*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_192: 232*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_AES_256: 233*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_128: 234*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_192: 235*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_SERPENT_256: 236*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_128: 237*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_TWOFISH_256: 238*6d92bdf4SRichard Henderson ctx->blocksize = 16; 239*6d92bdf4SRichard Henderson break; 240*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_3DES: 241*6d92bdf4SRichard Henderson case QCRYPTO_CIPHER_ALG_CAST5_128: 242*6d92bdf4SRichard Henderson ctx->blocksize = 8; 243*6d92bdf4SRichard Henderson break; 244*6d92bdf4SRichard Henderson default: 245*6d92bdf4SRichard Henderson g_assert_not_reached(); 246*6d92bdf4SRichard Henderson } 247*6d92bdf4SRichard Henderson } 248*6d92bdf4SRichard Henderson g_assert(is_power_of_2(ctx->blocksize)); 249*6d92bdf4SRichard Henderson 250*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 251*6d92bdf4SRichard Henderson if (mode == QCRYPTO_CIPHER_MODE_XTS) { 252*6d92bdf4SRichard Henderson if (ctx->blocksize != XTS_BLOCK_SIZE) { 253*6d92bdf4SRichard Henderson error_setg(errp, 254*6d92bdf4SRichard Henderson "Cipher block size %zu must equal XTS block size %d", 255*6d92bdf4SRichard Henderson ctx->blocksize, XTS_BLOCK_SIZE); 256*6d92bdf4SRichard Henderson goto error; 257*6d92bdf4SRichard Henderson } 258*6d92bdf4SRichard Henderson ctx->iv = g_new0(uint8_t, ctx->blocksize); 259*6d92bdf4SRichard Henderson } 260*6d92bdf4SRichard Henderson#endif 261*6d92bdf4SRichard Henderson 262*6d92bdf4SRichard Henderson return ctx; 263*6d92bdf4SRichard Henderson 264*6d92bdf4SRichard Henderson error: 265*6d92bdf4SRichard Henderson qcrypto_gcrypt_cipher_free_ctx(ctx, mode); 266*6d92bdf4SRichard Henderson return NULL; 267*6d92bdf4SRichard Henderson} 268*6d92bdf4SRichard Henderson 269*6d92bdf4SRichard Henderson 270*6d92bdf4SRichard Hendersonstatic void 271*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) 272*6d92bdf4SRichard Henderson{ 273*6d92bdf4SRichard Henderson qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode); 274*6d92bdf4SRichard Henderson} 275*6d92bdf4SRichard Henderson 276*6d92bdf4SRichard Henderson 277*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 278*6d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_encrypt(const void *ctx, 279*6d92bdf4SRichard Henderson size_t length, 280*6d92bdf4SRichard Henderson uint8_t *dst, 281*6d92bdf4SRichard Henderson const uint8_t *src) 282*6d92bdf4SRichard Henderson{ 283*6d92bdf4SRichard Henderson gcry_error_t err; 284*6d92bdf4SRichard Henderson err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 285*6d92bdf4SRichard Henderson g_assert(err == 0); 286*6d92bdf4SRichard Henderson} 287*6d92bdf4SRichard Henderson 288*6d92bdf4SRichard Hendersonstatic void qcrypto_gcrypt_xts_decrypt(const void *ctx, 289*6d92bdf4SRichard Henderson size_t length, 290*6d92bdf4SRichard Henderson uint8_t *dst, 291*6d92bdf4SRichard Henderson const uint8_t *src) 292*6d92bdf4SRichard Henderson{ 293*6d92bdf4SRichard Henderson gcry_error_t err; 294*6d92bdf4SRichard Henderson err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 295*6d92bdf4SRichard Henderson g_assert(err == 0); 296*6d92bdf4SRichard Henderson} 297*6d92bdf4SRichard Henderson#endif 298*6d92bdf4SRichard Henderson 299*6d92bdf4SRichard Hendersonstatic int 300*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, 301*6d92bdf4SRichard Henderson const void *in, 302*6d92bdf4SRichard Henderson void *out, 303*6d92bdf4SRichard Henderson size_t len, 304*6d92bdf4SRichard Henderson Error **errp) 305*6d92bdf4SRichard Henderson{ 306*6d92bdf4SRichard Henderson QCryptoCipherGcrypt *ctx = cipher->opaque; 307*6d92bdf4SRichard Henderson gcry_error_t err; 308*6d92bdf4SRichard Henderson 309*6d92bdf4SRichard Henderson if (len & (ctx->blocksize - 1)) { 310*6d92bdf4SRichard Henderson error_setg(errp, "Length %zu must be a multiple of block size %zu", 311*6d92bdf4SRichard Henderson len, ctx->blocksize); 312*6d92bdf4SRichard Henderson return -1; 313*6d92bdf4SRichard Henderson } 314*6d92bdf4SRichard Henderson 315*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 316*6d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 317*6d92bdf4SRichard Henderson xts_encrypt(ctx->handle, ctx->tweakhandle, 318*6d92bdf4SRichard Henderson qcrypto_gcrypt_xts_encrypt, 319*6d92bdf4SRichard Henderson qcrypto_gcrypt_xts_decrypt, 320*6d92bdf4SRichard Henderson ctx->iv, len, out, in); 321*6d92bdf4SRichard Henderson return 0; 322*6d92bdf4SRichard Henderson } 323*6d92bdf4SRichard Henderson#endif 324*6d92bdf4SRichard Henderson 325*6d92bdf4SRichard Henderson err = gcry_cipher_encrypt(ctx->handle, 326*6d92bdf4SRichard Henderson out, len, 327*6d92bdf4SRichard Henderson in, len); 328*6d92bdf4SRichard Henderson if (err != 0) { 329*6d92bdf4SRichard Henderson error_setg(errp, "Cannot encrypt data: %s", 330*6d92bdf4SRichard Henderson gcry_strerror(err)); 331*6d92bdf4SRichard Henderson return -1; 332*6d92bdf4SRichard Henderson } 333*6d92bdf4SRichard Henderson 334*6d92bdf4SRichard Henderson return 0; 335*6d92bdf4SRichard Henderson} 336*6d92bdf4SRichard Henderson 337*6d92bdf4SRichard Henderson 338*6d92bdf4SRichard Hendersonstatic int 339*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, 340*6d92bdf4SRichard Henderson const void *in, 341*6d92bdf4SRichard Henderson void *out, 342*6d92bdf4SRichard Henderson size_t len, 343*6d92bdf4SRichard Henderson Error **errp) 344*6d92bdf4SRichard Henderson{ 345*6d92bdf4SRichard Henderson QCryptoCipherGcrypt *ctx = cipher->opaque; 346*6d92bdf4SRichard Henderson gcry_error_t err; 347*6d92bdf4SRichard Henderson 348*6d92bdf4SRichard Henderson if (len & (ctx->blocksize - 1)) { 349*6d92bdf4SRichard Henderson error_setg(errp, "Length %zu must be a multiple of block size %zu", 350*6d92bdf4SRichard Henderson len, ctx->blocksize); 351*6d92bdf4SRichard Henderson return -1; 352*6d92bdf4SRichard Henderson } 353*6d92bdf4SRichard Henderson 354*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 355*6d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 356*6d92bdf4SRichard Henderson xts_decrypt(ctx->handle, ctx->tweakhandle, 357*6d92bdf4SRichard Henderson qcrypto_gcrypt_xts_encrypt, 358*6d92bdf4SRichard Henderson qcrypto_gcrypt_xts_decrypt, 359*6d92bdf4SRichard Henderson ctx->iv, len, out, in); 360*6d92bdf4SRichard Henderson return 0; 361*6d92bdf4SRichard Henderson } 362*6d92bdf4SRichard Henderson#endif 363*6d92bdf4SRichard Henderson 364*6d92bdf4SRichard Henderson err = gcry_cipher_decrypt(ctx->handle, 365*6d92bdf4SRichard Henderson out, len, 366*6d92bdf4SRichard Henderson in, len); 367*6d92bdf4SRichard Henderson if (err != 0) { 368*6d92bdf4SRichard Henderson error_setg(errp, "Cannot decrypt data: %s", 369*6d92bdf4SRichard Henderson gcry_strerror(err)); 370*6d92bdf4SRichard Henderson return -1; 371*6d92bdf4SRichard Henderson } 372*6d92bdf4SRichard Henderson 373*6d92bdf4SRichard Henderson return 0; 374*6d92bdf4SRichard Henderson} 375*6d92bdf4SRichard Henderson 376*6d92bdf4SRichard Hendersonstatic int 377*6d92bdf4SRichard Hendersonqcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, 378*6d92bdf4SRichard Henderson const uint8_t *iv, size_t niv, 379*6d92bdf4SRichard Henderson Error **errp) 380*6d92bdf4SRichard Henderson{ 381*6d92bdf4SRichard Henderson QCryptoCipherGcrypt *ctx = cipher->opaque; 382*6d92bdf4SRichard Henderson gcry_error_t err; 383*6d92bdf4SRichard Henderson 384*6d92bdf4SRichard Henderson if (niv != ctx->blocksize) { 385*6d92bdf4SRichard Henderson error_setg(errp, "Expected IV size %zu not %zu", 386*6d92bdf4SRichard Henderson ctx->blocksize, niv); 387*6d92bdf4SRichard Henderson return -1; 388*6d92bdf4SRichard Henderson } 389*6d92bdf4SRichard Henderson 390*6d92bdf4SRichard Henderson#ifdef CONFIG_QEMU_PRIVATE_XTS 391*6d92bdf4SRichard Henderson if (ctx->iv) { 392*6d92bdf4SRichard Henderson memcpy(ctx->iv, iv, niv); 393*6d92bdf4SRichard Henderson return 0; 394*6d92bdf4SRichard Henderson } 395*6d92bdf4SRichard Henderson#endif 396*6d92bdf4SRichard Henderson 397*6d92bdf4SRichard Henderson if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { 398*6d92bdf4SRichard Henderson err = gcry_cipher_setctr(ctx->handle, iv, niv); 399*6d92bdf4SRichard Henderson if (err != 0) { 400*6d92bdf4SRichard Henderson error_setg(errp, "Cannot set Counter: %s", 401*6d92bdf4SRichard Henderson gcry_strerror(err)); 402*6d92bdf4SRichard Henderson return -1; 403*6d92bdf4SRichard Henderson } 404*6d92bdf4SRichard Henderson } else { 405*6d92bdf4SRichard Henderson gcry_cipher_reset(ctx->handle); 406*6d92bdf4SRichard Henderson err = gcry_cipher_setiv(ctx->handle, iv, niv); 407*6d92bdf4SRichard Henderson if (err != 0) { 408*6d92bdf4SRichard Henderson error_setg(errp, "Cannot set IV: %s", 409*6d92bdf4SRichard Henderson gcry_strerror(err)); 410*6d92bdf4SRichard Henderson return -1; 411*6d92bdf4SRichard Henderson } 412*6d92bdf4SRichard Henderson } 413*6d92bdf4SRichard Henderson 414*6d92bdf4SRichard Henderson return 0; 415*6d92bdf4SRichard Henderson} 416*6d92bdf4SRichard Henderson 417*6d92bdf4SRichard Henderson 418*6d92bdf4SRichard Hendersonstatic struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { 419*6d92bdf4SRichard Henderson .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt, 420*6d92bdf4SRichard Henderson .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt, 421*6d92bdf4SRichard Henderson .cipher_setiv = qcrypto_gcrypt_cipher_setiv, 422*6d92bdf4SRichard Henderson .cipher_free = qcrypto_gcrypt_cipher_ctx_free, 423*6d92bdf4SRichard Henderson}; 424