mirror of https://gitee.com/openkylin/qemu.git
crypto/gcrypt: Split QCryptoCipherGcrypt into subclasses
With gcrypt, most of the dispatch happens in the library, so there aren't many classes to create. However, we can still create separate dispatch for CTR mode, and for CONFIG_QEMU_PRIVATE_XTS, which avoids needing to check for these modes at runtime. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
53ddad9b83
commit
1b010d9339
|
@ -24,8 +24,6 @@
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
static const struct QCryptoCipherDriver qcrypto_cipher_lib_driver;
|
|
||||||
|
|
||||||
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||||
QCryptoCipherMode mode)
|
QCryptoCipherMode mode)
|
||||||
{
|
{
|
||||||
|
@ -57,36 +55,212 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
typedef struct QCryptoCipherGcrypt {
|
||||||
struct QCryptoCipherGcrypt {
|
|
||||||
QCryptoCipher base;
|
QCryptoCipher base;
|
||||||
gcry_cipher_hd_t handle;
|
gcry_cipher_hd_t handle;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
gcry_cipher_hd_t tweakhandle;
|
gcry_cipher_hd_t tweakhandle;
|
||||||
/* Initialization vector or Counter */
|
uint8_t iv[XTS_BLOCK_SIZE];
|
||||||
uint8_t *iv;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
} QCryptoCipherGcrypt;
|
||||||
|
|
||||||
static void
|
|
||||||
qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
|
static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
|
||||||
QCryptoCipherMode mode)
|
|
||||||
{
|
{
|
||||||
if (!ctx) {
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gcry_cipher_close(ctx->handle);
|
gcry_cipher_close(ctx->handle);
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
|
||||||
gcry_cipher_close(ctx->tweakhandle);
|
|
||||||
}
|
|
||||||
g_free(ctx->iv);
|
|
||||||
#endif
|
|
||||||
g_free(ctx);
|
g_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
|
||||||
|
void *out, size_t len, Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
if (len & (ctx->blocksize - 1)) {
|
||||||
|
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||||
|
len, ctx->blocksize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
|
||||||
|
void *out, size_t len, Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
if (len & (ctx->blocksize - 1)) {
|
||||||
|
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||||
|
len, ctx->blocksize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot decrypt data: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
if (niv != ctx->blocksize) {
|
||||||
|
error_setg(errp, "Expected IV size %zu not %zu",
|
||||||
|
ctx->blocksize, niv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_cipher_reset(ctx->handle);
|
||||||
|
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
gcry_error_t err;
|
||||||
|
|
||||||
|
if (niv != ctx->blocksize) {
|
||||||
|
error_setg(errp, "Expected IV size %zu not %zu",
|
||||||
|
ctx->blocksize, niv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
||||||
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
|
||||||
|
.cipher_encrypt = qcrypto_gcrypt_encrypt,
|
||||||
|
.cipher_decrypt = qcrypto_gcrypt_decrypt,
|
||||||
|
.cipher_setiv = qcrypto_gcrypt_setiv,
|
||||||
|
.cipher_free = qcrypto_gcrypt_ctx_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
|
||||||
|
.cipher_encrypt = qcrypto_gcrypt_encrypt,
|
||||||
|
.cipher_decrypt = qcrypto_gcrypt_decrypt,
|
||||||
|
.cipher_setiv = qcrypto_gcrypt_ctr_setiv,
|
||||||
|
.cipher_free = qcrypto_gcrypt_ctx_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
|
static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
|
||||||
|
gcry_cipher_close(ctx->tweakhandle);
|
||||||
|
qcrypto_gcrypt_ctx_free(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_gcrypt_xts_wrape(const void *ctx, size_t length,
|
||||||
|
uint8_t *dst, const uint8_t *src)
|
||||||
|
{
|
||||||
|
gcry_error_t err;
|
||||||
|
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||||
|
g_assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_gcrypt_xts_wrapd(const void *ctx, size_t length,
|
||||||
|
uint8_t *dst, const uint8_t *src)
|
||||||
|
{
|
||||||
|
gcry_error_t err;
|
||||||
|
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||||
|
g_assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in,
|
||||||
|
void *out, size_t len, Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
|
||||||
|
if (len & (ctx->blocksize - 1)) {
|
||||||
|
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||||
|
len, ctx->blocksize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||||
|
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
|
||||||
|
ctx->iv, len, out, in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in,
|
||||||
|
void *out, size_t len, Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
|
||||||
|
if (len & (ctx->blocksize - 1)) {
|
||||||
|
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||||
|
len, ctx->blocksize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||||
|
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
|
||||||
|
ctx->iv, len, out, in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher,
|
||||||
|
const uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
||||||
|
|
||||||
|
if (niv != ctx->blocksize) {
|
||||||
|
error_setg(errp, "Expected IV size %zu not %zu",
|
||||||
|
ctx->blocksize, niv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ctx->iv, iv, niv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct QCryptoCipherDriver qcrypto_gcrypt_xts_driver = {
|
||||||
|
.cipher_encrypt = qcrypto_gcrypt_xts_encrypt,
|
||||||
|
.cipher_decrypt = qcrypto_gcrypt_xts_decrypt,
|
||||||
|
.cipher_setiv = qcrypto_gcrypt_xts_setiv,
|
||||||
|
.cipher_free = qcrypto_gcrypt_xts_ctx_free,
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_QEMU_PRIVATE_XTS */
|
||||||
|
|
||||||
|
|
||||||
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
QCryptoCipherMode mode,
|
QCryptoCipherMode mode,
|
||||||
|
@ -95,32 +269,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
QCryptoCipherGcrypt *ctx;
|
QCryptoCipherGcrypt *ctx;
|
||||||
|
const QCryptoCipherDriver *drv;
|
||||||
gcry_error_t err;
|
gcry_error_t err;
|
||||||
int gcryalg, gcrymode;
|
int gcryalg, gcrymode;
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
|
||||||
break;
|
|
||||||
case QCRYPTO_CIPHER_MODE_XTS:
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
|
||||||
#else
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_XTS;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case QCRYPTO_CIPHER_MODE_CBC:
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_CBC;
|
|
||||||
break;
|
|
||||||
case QCRYPTO_CIPHER_MODE_CTR:
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_CTR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error_setg(errp, "Unsupported cipher mode %s",
|
|
||||||
QCryptoCipherMode_str(mode));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -129,54 +281,70 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
gcryalg = GCRY_CIPHER_DES;
|
gcryalg = GCRY_CIPHER_DES;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_3DES:
|
case QCRYPTO_CIPHER_ALG_3DES:
|
||||||
gcryalg = GCRY_CIPHER_3DES;
|
gcryalg = GCRY_CIPHER_3DES;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
gcryalg = GCRY_CIPHER_AES128;
|
gcryalg = GCRY_CIPHER_AES128;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
gcryalg = GCRY_CIPHER_AES192;
|
gcryalg = GCRY_CIPHER_AES192;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
gcryalg = GCRY_CIPHER_AES256;
|
gcryalg = GCRY_CIPHER_AES256;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||||
gcryalg = GCRY_CIPHER_CAST5;
|
gcryalg = GCRY_CIPHER_CAST5;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||||
gcryalg = GCRY_CIPHER_SERPENT128;
|
gcryalg = GCRY_CIPHER_SERPENT128;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||||
gcryalg = GCRY_CIPHER_SERPENT192;
|
gcryalg = GCRY_CIPHER_SERPENT192;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||||
gcryalg = GCRY_CIPHER_SERPENT256;
|
gcryalg = GCRY_CIPHER_SERPENT256;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||||
gcryalg = GCRY_CIPHER_TWOFISH128;
|
gcryalg = GCRY_CIPHER_TWOFISH128;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||||
gcryalg = GCRY_CIPHER_TWOFISH;
|
gcryalg = GCRY_CIPHER_TWOFISH;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher algorithm %s",
|
error_setg(errp, "Unsupported cipher algorithm %s",
|
||||||
QCryptoCipherAlgorithm_str(alg));
|
QCryptoCipherAlgorithm_str(alg));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drv = &qcrypto_gcrypt_driver;
|
||||||
|
switch (mode) {
|
||||||
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||||
|
break;
|
||||||
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
|
drv = &qcrypto_gcrypt_xts_driver;
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||||
|
#else
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_XTS;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_CBC;
|
||||||
|
break;
|
||||||
|
case QCRYPTO_CIPHER_MODE_CTR:
|
||||||
|
drv = &qcrypto_gcrypt_ctr_driver;
|
||||||
|
gcrymode = GCRY_CIPHER_MODE_CTR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unsupported cipher mode %s",
|
||||||
|
QCryptoCipherMode_str(mode));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ctx = g_new0(QCryptoCipherGcrypt, 1);
|
ctx = g_new0(QCryptoCipherGcrypt, 1);
|
||||||
|
ctx->base.driver = drv;
|
||||||
|
|
||||||
err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
|
err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -184,8 +352,16 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
|
||||||
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
|
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Cipher block size %zu must equal XTS block size %d",
|
||||||
|
ctx->blocksize, XTS_BLOCK_SIZE);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
error_setg(errp, "Cannot initialize cipher: %s",
|
error_setg(errp, "Cannot initialize cipher: %s",
|
||||||
|
@ -203,224 +379,31 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||||
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
|
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
|
||||||
g_free(rfbkey);
|
g_free(rfbkey);
|
||||||
ctx->blocksize = 8;
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
nkey /= 2;
|
nkey /= 2;
|
||||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
error_setg(errp, "Cannot set key: %s",
|
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
|
||||||
gcry_strerror(err));
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (err != 0) {
|
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||||
error_setg(errp, "Cannot set key: %s",
|
|
||||||
gcry_strerror(err));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
switch (alg) {
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
|
||||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
|
||||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
|
||||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
|
||||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
|
||||||
ctx->blocksize = 16;
|
|
||||||
break;
|
|
||||||
case QCRYPTO_CIPHER_ALG_3DES:
|
|
||||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
|
||||||
ctx->blocksize = 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_assert(is_power_of_2(ctx->blocksize));
|
if (err != 0) {
|
||||||
|
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
goto error;
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
|
||||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Cipher block size %zu must equal XTS block size %d",
|
|
||||||
ctx->blocksize, XTS_BLOCK_SIZE);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
ctx->base.driver = &qcrypto_cipher_lib_driver;
|
|
||||||
return &ctx->base;
|
return &ctx->base;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
|
gcry_cipher_close(ctx->tweakhandle);
|
||||||
|
#endif
|
||||||
|
gcry_cipher_close(ctx->handle);
|
||||||
|
g_free(ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
|
|
||||||
{
|
|
||||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
|
||||||
|
|
||||||
qcrypto_gcrypt_cipher_free_ctx(ctx, cipher->mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
|
||||||
size_t length,
|
|
||||||
uint8_t *dst,
|
|
||||||
const uint8_t *src)
|
|
||||||
{
|
|
||||||
gcry_error_t err;
|
|
||||||
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
|
||||||
g_assert(err == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
|
|
||||||
size_t length,
|
|
||||||
uint8_t *dst,
|
|
||||||
const uint8_t *src)
|
|
||||||
{
|
|
||||||
gcry_error_t err;
|
|
||||||
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
|
||||||
g_assert(err == 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
|
||||||
const void *in,
|
|
||||||
void *out,
|
|
||||||
size_t len,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
if (len & (ctx->blocksize - 1)) {
|
|
||||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
|
||||||
len, ctx->blocksize);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
|
||||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
|
||||||
qcrypto_gcrypt_xts_encrypt,
|
|
||||||
qcrypto_gcrypt_xts_decrypt,
|
|
||||||
ctx->iv, len, out, in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = gcry_cipher_encrypt(ctx->handle,
|
|
||||||
out, len,
|
|
||||||
in, len);
|
|
||||||
if (err != 0) {
|
|
||||||
error_setg(errp, "Cannot encrypt data: %s",
|
|
||||||
gcry_strerror(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
|
|
||||||
const void *in,
|
|
||||||
void *out,
|
|
||||||
size_t len,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
if (len & (ctx->blocksize - 1)) {
|
|
||||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
|
||||||
len, ctx->blocksize);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
|
||||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
|
||||||
qcrypto_gcrypt_xts_encrypt,
|
|
||||||
qcrypto_gcrypt_xts_decrypt,
|
|
||||||
ctx->iv, len, out, in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = gcry_cipher_decrypt(ctx->handle,
|
|
||||||
out, len,
|
|
||||||
in, len);
|
|
||||||
if (err != 0) {
|
|
||||||
error_setg(errp, "Cannot decrypt data: %s",
|
|
||||||
gcry_strerror(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
|
|
||||||
const uint8_t *iv, size_t niv,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
if (niv != ctx->blocksize) {
|
|
||||||
error_setg(errp, "Expected IV size %zu not %zu",
|
|
||||||
ctx->blocksize, niv);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
|
||||||
if (ctx->iv) {
|
|
||||||
memcpy(ctx->iv, iv, niv);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
|
|
||||||
err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
|
||||||
if (err != 0) {
|
|
||||||
error_setg(errp, "Cannot set Counter: %s",
|
|
||||||
gcry_strerror(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gcry_cipher_reset(ctx->handle);
|
|
||||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
|
||||||
if (err != 0) {
|
|
||||||
error_setg(errp, "Cannot set IV: %s",
|
|
||||||
gcry_strerror(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct QCryptoCipherDriver qcrypto_cipher_lib_driver = {
|
|
||||||
.cipher_encrypt = qcrypto_gcrypt_cipher_encrypt,
|
|
||||||
.cipher_decrypt = qcrypto_gcrypt_cipher_decrypt,
|
|
||||||
.cipher_setiv = qcrypto_gcrypt_cipher_setiv,
|
|
||||||
.cipher_free = qcrypto_gcrypt_cipher_ctx_free,
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue