crypto: ensure XTS is only used with ciphers with 16 byte blocks
The XTS cipher mode needs to be used with a cipher which has a block size of 16 bytes. If a mis-matching block size is used, the code will either corrupt memory beyond the IV array, or not fully encrypt/decrypt the IV. This fixes a memory corruption crash when attempting to use cast5-128 with xts, since the former has an 8 byte block size. A test case is added to ensure the cipher creation fails with such an invalid combination. Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
c2a57aae9a
commit
a5d2f44d0d
@ -192,6 +192,12 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (cipher->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);
|
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +361,13 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode == QCRYPTO_CIPHER_MODE_XTS &&
|
||||||
|
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);
|
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||||
cipher->opaque = ctx;
|
cipher->opaque = ctx;
|
||||||
|
|
||||||
@ -456,11 +463,6 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_XTS:
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
|
||||||
error_setg(errp, "Block size must be %d not %zu",
|
|
||||||
XTS_BLOCK_SIZE, ctx->blocksize);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||||
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
||||||
ctx->iv, len, out, in);
|
ctx->iv, len, out, in);
|
||||||
|
@ -370,6 +370,17 @@ static QCryptoCipherTestData test_data[] = {
|
|||||||
"eb4a427d1923ce3ff262735779a418f2"
|
"eb4a427d1923ce3ff262735779a418f2"
|
||||||
"0a282df920147beabe421ee5319d0568",
|
"0a282df920147beabe421ee5319d0568",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/* Bad config - cast5-128 has 8 byte block size
|
||||||
|
* which is incompatible with XTS
|
||||||
|
*/
|
||||||
|
.path = "/crypto/cipher/cast5-xts-128",
|
||||||
|
.alg = QCRYPTO_CIPHER_ALG_CAST5_128,
|
||||||
|
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||||
|
.key =
|
||||||
|
"27182818284590452353602874713526"
|
||||||
|
"31415926535897932384626433832795",
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -432,15 +443,23 @@ static void test_cipher(const void *opaque)
|
|||||||
const QCryptoCipherTestData *data = opaque;
|
const QCryptoCipherTestData *data = opaque;
|
||||||
|
|
||||||
QCryptoCipher *cipher;
|
QCryptoCipher *cipher;
|
||||||
uint8_t *key, *iv, *ciphertext, *plaintext, *outtext;
|
uint8_t *key, *iv = NULL, *ciphertext = NULL,
|
||||||
size_t nkey, niv, nciphertext, nplaintext;
|
*plaintext = NULL, *outtext = NULL;
|
||||||
char *outtexthex;
|
size_t nkey, niv = 0, nciphertext = 0, nplaintext = 0;
|
||||||
|
char *outtexthex = NULL;
|
||||||
size_t ivsize, keysize, blocksize;
|
size_t ivsize, keysize, blocksize;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
nkey = unhex_string(data->key, &key);
|
nkey = unhex_string(data->key, &key);
|
||||||
niv = unhex_string(data->iv, &iv);
|
if (data->iv) {
|
||||||
nciphertext = unhex_string(data->ciphertext, &ciphertext);
|
niv = unhex_string(data->iv, &iv);
|
||||||
nplaintext = unhex_string(data->plaintext, &plaintext);
|
}
|
||||||
|
if (data->ciphertext) {
|
||||||
|
nciphertext = unhex_string(data->ciphertext, &ciphertext);
|
||||||
|
}
|
||||||
|
if (data->plaintext) {
|
||||||
|
nplaintext = unhex_string(data->plaintext, &plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
g_assert(nciphertext == nplaintext);
|
g_assert(nciphertext == nplaintext);
|
||||||
|
|
||||||
@ -449,8 +468,15 @@ static void test_cipher(const void *opaque)
|
|||||||
cipher = qcrypto_cipher_new(
|
cipher = qcrypto_cipher_new(
|
||||||
data->alg, data->mode,
|
data->alg, data->mode,
|
||||||
key, nkey,
|
key, nkey,
|
||||||
&error_abort);
|
&err);
|
||||||
g_assert(cipher != NULL);
|
if (data->plaintext) {
|
||||||
|
g_assert(err == NULL);
|
||||||
|
g_assert(cipher != NULL);
|
||||||
|
} else {
|
||||||
|
error_free_or_abort(&err);
|
||||||
|
g_assert(cipher == NULL);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
keysize = qcrypto_cipher_get_key_len(data->alg);
|
keysize = qcrypto_cipher_get_key_len(data->alg);
|
||||||
blocksize = qcrypto_cipher_get_block_len(data->alg);
|
blocksize = qcrypto_cipher_get_block_len(data->alg);
|
||||||
@ -498,6 +524,7 @@ static void test_cipher(const void *opaque)
|
|||||||
|
|
||||||
g_assert_cmpstr(outtexthex, ==, data->plaintext);
|
g_assert_cmpstr(outtexthex, ==, data->plaintext);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
g_free(outtext);
|
g_free(outtext);
|
||||||
g_free(outtexthex);
|
g_free(outtexthex);
|
||||||
g_free(key);
|
g_free(key);
|
||||||
|
Loading…
Reference in New Issue
Block a user