crypto: refactor code for dealing with AES cipher

The built-in and nettle cipher backends for AES maintain
two separate AES contexts, one for encryption and one for
decryption. This is going to be inconvenient for the future
code dealing with XTS, so wrap them up in a single struct
so there is just one pointer to pass around for both
encryption and decryption.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-02-11 14:05:21 +00:00
parent 84f7f180b0
commit e3ba0b6701
2 changed files with 109 additions and 74 deletions

View file

@ -22,10 +22,14 @@
#include "crypto/aes.h"
#include "crypto/desrfb.h"
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
struct QCryptoCipherBuiltinAESContext {
AES_KEY enc;
AES_KEY dec;
};
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
struct QCryptoCipherBuiltinAES {
AES_KEY encrypt_key;
AES_KEY decrypt_key;
QCryptoCipherBuiltinAESContext key;
uint8_t iv[AES_BLOCK_SIZE];
};
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
@ -67,6 +71,58 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
}
static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
const void *in,
void *out,
size_t len)
{
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_encrypt(inptr, outptr, key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_encrypt(tmp1, tmp2, key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
}
static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
const void *in,
void *out,
size_t len)
{
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_decrypt(inptr, outptr, key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_decrypt(tmp1, tmp2, key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
}
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
const void *in,
void *out,
@ -75,29 +131,18 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
} else {
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
in, out, len);
break;
case QCRYPTO_CIPHER_MODE_CBC:
AES_cbc_encrypt(in, out, len,
&ctxt->state.aes.encrypt_key,
&ctxt->state.aes.key.enc,
ctxt->state.aes.iv, 1);
break;
default:
g_assert_not_reached();
}
return 0;
@ -112,29 +157,18 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
{
QCryptoCipherBuiltin *ctxt = cipher->opaque;
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
const uint8_t *inptr = in;
uint8_t *outptr = out;
while (len) {
if (len > AES_BLOCK_SIZE) {
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
inptr += AES_BLOCK_SIZE;
outptr += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else {
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
memcpy(tmp1, inptr, len);
/* Fill with 0 to avoid valgrind uninitialized reads */
memset(tmp1 + len, 0, sizeof(tmp1) - len);
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.decrypt_key);
memcpy(outptr, tmp2, len);
len = 0;
}
}
} else {
switch (cipher->mode) {
case QCRYPTO_CIPHER_MODE_ECB:
qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
in, out, len);
break;
case QCRYPTO_CIPHER_MODE_CBC:
AES_cbc_encrypt(in, out, len,
&ctxt->state.aes.decrypt_key,
&ctxt->state.aes.key.dec,
ctxt->state.aes.iv, 0);
break;
default:
g_assert_not_reached();
}
return 0;
@ -173,12 +207,12 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
ctxt = g_new0(QCryptoCipherBuiltin, 1);
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
error_setg(errp, "Failed to set encryption key");
goto error;
}
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
error_setg(errp, "Failed to set decryption key");
goto error;
}