aboutsummaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2015-10-16 16:35:06 +0100
committerDaniel P. Berrange <berrange@redhat.com>2015-10-22 19:03:08 +0100
commit3a661f1eabf7e8db66e28489884d9b54aacb94ea (patch)
tree4a0b45548a6eb797c9c254797f065b2b5cd9b33e /crypto
parenteb2a770b178b9040c3fc04ee31dc38d1775db09a (diff)
downloadqemu-3a661f1eabf7e8db66e28489884d9b54aacb94ea.zip
qemu-3a661f1eabf7e8db66e28489884d9b54aacb94ea.tar.gz
qemu-3a661f1eabf7e8db66e28489884d9b54aacb94ea.tar.bz2
crypto: add sanity checking of plaintext/ciphertext length
When encrypting/decrypting data, the plaintext/ciphertext buffers are required to be a multiple of the cipher block size. If this is not done, nettle will abort and gcrypt will report an error. To get consistent behaviour add explicit checks upfront for the buffer sizes. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/cipher-builtin.c15
-rw-r--r--crypto/cipher-gcrypt.c61
-rw-r--r--crypto/cipher-nettle.c28
3 files changed, 80 insertions, 24 deletions
diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c
index 37e1a19..39e31a7 100644
--- a/crypto/cipher-builtin.c
+++ b/crypto/cipher-builtin.c
@@ -39,6 +39,7 @@ struct QCryptoCipherBuiltin {
QCryptoCipherBuiltinAES aes;
QCryptoCipherBuiltinDESRFB desrfb;
} state;
+ size_t blocksize;
void (*free)(QCryptoCipher *cipher);
int (*setiv)(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
@@ -181,6 +182,7 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
goto error;
}
+ ctxt->blocksize = AES_BLOCK_SIZE;
ctxt->free = qcrypto_cipher_free_aes;
ctxt->setiv = qcrypto_cipher_setiv_aes;
ctxt->encrypt = qcrypto_cipher_encrypt_aes;
@@ -282,6 +284,7 @@ static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
memcpy(ctxt->state.desrfb.key, key, nkey);
ctxt->state.desrfb.nkey = nkey;
+ ctxt->blocksize = 8;
ctxt->free = qcrypto_cipher_free_des_rfb;
ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
@@ -370,6 +373,12 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ if (len % ctxt->blocksize) {
+ error_setg(errp, "Length %zu must be a multiple of block size %zu",
+ len, ctxt->blocksize);
+ return -1;
+ }
+
return ctxt->encrypt(cipher, in, out, len, errp);
}
@@ -382,6 +391,12 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ if (len % ctxt->blocksize) {
+ error_setg(errp, "Length %zu must be a multiple of block size %zu",
+ len, ctxt->blocksize);
+ return -1;
+ }
+
return ctxt->decrypt(cipher, in, out, len, errp);
}
diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
index 8cfc562..c4f8114 100644
--- a/crypto/cipher-gcrypt.c
+++ b/crypto/cipher-gcrypt.c
@@ -34,6 +34,11 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
}
}
+typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
+struct QCryptoCipherGcrypt {
+ gcry_cipher_hd_t handle;
+ size_t blocksize;
+};
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
@@ -41,7 +46,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
Error **errp)
{
QCryptoCipher *cipher;
- gcry_cipher_hd_t handle;
+ QCryptoCipherGcrypt *ctx;
gcry_error_t err;
int gcryalg, gcrymode;
@@ -87,7 +92,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
cipher->alg = alg;
cipher->mode = mode;
- err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
+ ctx = g_new0(QCryptoCipherGcrypt, 1);
+
+ err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gcry_strerror(err));
@@ -100,10 +107,12 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
* bizarre RFB variant of DES :-)
*/
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
- err = gcry_cipher_setkey(handle, rfbkey, nkey);
+ err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
g_free(rfbkey);
+ ctx->blocksize = 8;
} else {
- err = gcry_cipher_setkey(handle, key, nkey);
+ err = gcry_cipher_setkey(ctx->handle, key, nkey);
+ ctx->blocksize = 16;
}
if (err != 0) {
error_setg(errp, "Cannot set key: %s",
@@ -111,11 +120,12 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
goto error;
}
- cipher->opaque = handle;
+ cipher->opaque = ctx;
return cipher;
error:
- gcry_cipher_close(handle);
+ gcry_cipher_close(ctx->handle);
+ g_free(ctx);
g_free(cipher);
return NULL;
}
@@ -123,12 +133,13 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
void qcrypto_cipher_free(QCryptoCipher *cipher)
{
- gcry_cipher_hd_t handle;
+ QCryptoCipherGcrypt *ctx;
if (!cipher) {
return;
}
- handle = cipher->opaque;
- gcry_cipher_close(handle);
+ ctx = cipher->opaque;
+ gcry_cipher_close(ctx->handle);
+ g_free(ctx);
g_free(cipher);
}
@@ -139,10 +150,16 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
size_t len,
Error **errp)
{
- gcry_cipher_hd_t handle = cipher->opaque;
+ QCryptoCipherGcrypt *ctx = cipher->opaque;
gcry_error_t err;
- err = gcry_cipher_encrypt(handle,
+ if (len % ctx->blocksize) {
+ 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) {
@@ -161,10 +178,16 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
size_t len,
Error **errp)
{
- gcry_cipher_hd_t handle = cipher->opaque;
+ QCryptoCipherGcrypt *ctx = cipher->opaque;
gcry_error_t err;
- err = gcry_cipher_decrypt(handle,
+ if (len % ctx->blocksize) {
+ 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) {
@@ -180,11 +203,17 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
- gcry_cipher_hd_t handle = cipher->opaque;
+ QCryptoCipherGcrypt *ctx = cipher->opaque;
gcry_error_t err;
- gcry_cipher_reset(handle);
- err = gcry_cipher_setiv(handle, iv, niv);
+ 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));
diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c
index b01cb1c..7449338 100644
--- a/crypto/cipher-nettle.c
+++ b/crypto/cipher-nettle.c
@@ -69,7 +69,7 @@ struct QCryptoCipherNettle {
nettle_cipher_func *alg_encrypt;
nettle_cipher_func *alg_decrypt;
uint8_t *iv;
- size_t niv;
+ size_t blocksize;
};
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
@@ -125,7 +125,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
ctx->alg_encrypt = des_encrypt_wrapper;
ctx->alg_decrypt = des_decrypt_wrapper;
- ctx->niv = DES_BLOCK_SIZE;
+ ctx->blocksize = DES_BLOCK_SIZE;
break;
case QCRYPTO_CIPHER_ALG_AES_128:
@@ -140,14 +140,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
ctx->alg_encrypt = aes_encrypt_wrapper;
ctx->alg_decrypt = aes_decrypt_wrapper;
- ctx->niv = AES_BLOCK_SIZE;
+ ctx->blocksize = AES_BLOCK_SIZE;
break;
default:
error_setg(errp, "Unsupported cipher algorithm %d", alg);
goto error;
}
- ctx->iv = g_new0(uint8_t, ctx->niv);
+ ctx->iv = g_new0(uint8_t, ctx->blocksize);
cipher->opaque = ctx;
return cipher;
@@ -184,6 +184,12 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
{
QCryptoCipherNettle *ctx = cipher->opaque;
+ if (len % ctx->blocksize) {
+ error_setg(errp, "Length %zu must be a multiple of block size %zu",
+ len, ctx->blocksize);
+ return -1;
+ }
+
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
@@ -191,7 +197,7 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
case QCRYPTO_CIPHER_MODE_CBC:
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
- ctx->niv, ctx->iv,
+ ctx->blocksize, ctx->iv,
len, out, in);
break;
default:
@@ -211,6 +217,12 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
{
QCryptoCipherNettle *ctx = cipher->opaque;
+ if (len % ctx->blocksize) {
+ error_setg(errp, "Length %zu must be a multiple of block size %zu",
+ len, ctx->blocksize);
+ return -1;
+ }
+
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
@@ -219,7 +231,7 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
case QCRYPTO_CIPHER_MODE_CBC:
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
- ctx->alg_decrypt, ctx->niv, ctx->iv,
+ ctx->alg_decrypt, ctx->blocksize, ctx->iv,
len, out, in);
break;
default:
@@ -235,9 +247,9 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
Error **errp)
{
QCryptoCipherNettle *ctx = cipher->opaque;
- if (niv != ctx->niv) {
+ if (niv != ctx->blocksize) {
error_setg(errp, "Expected IV size %zu not %zu",
- ctx->niv, niv);
+ ctx->blocksize, niv);
return -1;
}
memcpy(ctx->iv, iv, niv);