aboutsummaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2020-08-28 10:05:23 -0700
committerDaniel P. Berrangé <berrange@redhat.com>2020-09-10 11:02:23 +0100
commit1b010d9339497b081c3b8ab4f98b2a21f2cae08d (patch)
treeb9d4fa22c8f2ff80578c155def5e3881778ba101 /crypto
parent53ddad9b8398ef95c38f60d849aa9edf85a07282 (diff)
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>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/cipher-gcrypt.c.inc493
1 files changed, 238 insertions, 255 deletions
diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
index 7a1fbc9745..42d4137534 100644
--- a/crypto/cipher-gcrypt.c.inc
+++ b/crypto/cipher-gcrypt.c.inc
@@ -24,8 +24,6 @@
#include <gcrypt.h>
-static const struct QCryptoCipherDriver qcrypto_cipher_lib_driver;
-
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
@@ -57,36 +55,212 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
}
}
-typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
-struct QCryptoCipherGcrypt {
+typedef struct QCryptoCipherGcrypt {
QCryptoCipher base;
gcry_cipher_hd_t handle;
size_t blocksize;
#ifdef CONFIG_QEMU_PRIVATE_XTS
gcry_cipher_hd_t tweakhandle;
- /* Initialization vector or Counter */
- uint8_t *iv;
+ uint8_t iv[XTS_BLOCK_SIZE];
#endif
-};
+} QCryptoCipherGcrypt;
+
-static void
-qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
- QCryptoCipherMode mode)
+static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
{
- if (!ctx) {
- return;
- }
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
gcry_cipher_close(ctx->handle);
+ 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
- if (mode == QCRYPTO_CIPHER_MODE_XTS) {
- gcry_cipher_close(ctx->tweakhandle);
+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;
}
- g_free(ctx->iv);
-#endif
- g_free(ctx);
+
+ 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,
QCryptoCipherMode mode,
@@ -95,32 +269,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
Error **errp)
{
QCryptoCipherGcrypt *ctx;
+ const QCryptoCipherDriver *drv;
gcry_error_t err;
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)) {
return NULL;
}
@@ -129,54 +281,70 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_DES_RFB:
gcryalg = GCRY_CIPHER_DES;
break;
-
case QCRYPTO_CIPHER_ALG_3DES:
gcryalg = GCRY_CIPHER_3DES;
break;
-
case QCRYPTO_CIPHER_ALG_AES_128:
gcryalg = GCRY_CIPHER_AES128;
break;
-
case QCRYPTO_CIPHER_ALG_AES_192:
gcryalg = GCRY_CIPHER_AES192;
break;
-
case QCRYPTO_CIPHER_ALG_AES_256:
gcryalg = GCRY_CIPHER_AES256;
break;
-
case QCRYPTO_CIPHER_ALG_CAST5_128:
gcryalg = GCRY_CIPHER_CAST5;
break;
-
case QCRYPTO_CIPHER_ALG_SERPENT_128:
gcryalg = GCRY_CIPHER_SERPENT128;
break;
-
case QCRYPTO_CIPHER_ALG_SERPENT_192:
gcryalg = GCRY_CIPHER_SERPENT192;
break;
-
case QCRYPTO_CIPHER_ALG_SERPENT_256:
gcryalg = GCRY_CIPHER_SERPENT256;
break;
-
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
gcryalg = GCRY_CIPHER_TWOFISH128;
break;
-
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
gcryalg = GCRY_CIPHER_TWOFISH;
break;
-
default:
error_setg(errp, "Unsupported cipher algorithm %s",
QCryptoCipherAlgorithm_str(alg));
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->base.driver = drv;
err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
if (err != 0) {
@@ -184,8 +352,16 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
gcry_strerror(err));
goto error;
}
+ ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
+
#ifdef CONFIG_QEMU_PRIVATE_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);
if (err != 0) {
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);
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
g_free(rfbkey);
- ctx->blocksize = 8;
} else {
#ifdef CONFIG_QEMU_PRIVATE_XTS
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
nkey /= 2;
- err = gcry_cipher_setkey(ctx->handle, key, nkey);
+ err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
if (err != 0) {
- error_setg(errp, "Cannot set key: %s",
- gcry_strerror(err));
+ error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
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
- if (err != 0) {
- 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();
- }
+ err = gcry_cipher_setkey(ctx->handle, key, nkey);
}
- g_assert(is_power_of_2(ctx->blocksize));
-
-#ifdef CONFIG_QEMU_PRIVATE_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;
- }
- ctx->iv = g_new0(uint8_t, ctx->blocksize);
+ if (err != 0) {
+ error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
+ goto error;
}
-#endif
- ctx->base.driver = &qcrypto_cipher_lib_driver;
return &ctx->base;
error:
- qcrypto_gcrypt_cipher_free_ctx(ctx, mode);
- 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;
- }
+ gcry_cipher_close(ctx->tweakhandle);
#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;
+ gcry_cipher_close(ctx->handle);
+ g_free(ctx);
+ return NULL;
}
-
-
-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,
-};