crypto: wire up XTS mode for cipher APIs

Introduce 'XTS' as a permitted mode for the cipher APIs.
With XTS the key provided must be twice the size of the
key normally required for any given algorithm. This is
because the key will be split into two pieces for use
in XTS mode.

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 e3ba0b6701
commit eaec903c5b
6 changed files with 405 additions and 46 deletions

View File

@ -21,6 +21,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "crypto/aes.h" #include "crypto/aes.h"
#include "crypto/desrfb.h" #include "crypto/desrfb.h"
#include "crypto/xts.h"
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
struct QCryptoCipherBuiltinAESContext { struct QCryptoCipherBuiltinAESContext {
@ -30,6 +31,7 @@ struct QCryptoCipherBuiltinAESContext {
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
struct QCryptoCipherBuiltinAES { struct QCryptoCipherBuiltinAES {
QCryptoCipherBuiltinAESContext key; QCryptoCipherBuiltinAESContext key;
QCryptoCipherBuiltinAESContext key_tweak;
uint8_t iv[AES_BLOCK_SIZE]; uint8_t iv[AES_BLOCK_SIZE];
}; };
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB; typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
@ -123,6 +125,30 @@ static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
} }
static void qcrypto_cipher_aes_xts_encrypt(const void *ctx,
size_t length,
uint8_t *dst,
const uint8_t *src)
{
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc,
src, dst, length);
}
static void qcrypto_cipher_aes_xts_decrypt(const void *ctx,
size_t length,
uint8_t *dst,
const uint8_t *src)
{
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec,
src, dst, length);
}
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
const void *in, const void *in,
void *out, void *out,
@ -141,6 +167,14 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
&ctxt->state.aes.key.enc, &ctxt->state.aes.key.enc,
ctxt->state.aes.iv, 1); ctxt->state.aes.iv, 1);
break; break;
case QCRYPTO_CIPHER_MODE_XTS:
xts_encrypt(&ctxt->state.aes.key,
&ctxt->state.aes.key_tweak,
qcrypto_cipher_aes_xts_encrypt,
qcrypto_cipher_aes_xts_decrypt,
ctxt->state.aes.iv,
len, out, in);
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -167,6 +201,14 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
&ctxt->state.aes.key.dec, &ctxt->state.aes.key.dec,
ctxt->state.aes.iv, 0); ctxt->state.aes.iv, 0);
break; break;
case QCRYPTO_CIPHER_MODE_XTS:
xts_decrypt(&ctxt->state.aes.key,
&ctxt->state.aes.key_tweak,
qcrypto_cipher_aes_xts_encrypt,
qcrypto_cipher_aes_xts_decrypt,
ctxt->state.aes.iv,
len, out, in);
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -200,21 +242,46 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
QCryptoCipherBuiltin *ctxt; QCryptoCipherBuiltin *ctxt;
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC && if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) { cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
error_setg(errp, "Unsupported cipher mode %d", cipher->mode); error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
return -1; return -1;
} }
ctxt = g_new0(QCryptoCipherBuiltin, 1); ctxt = g_new0(QCryptoCipherBuiltin, 1);
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) { if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
error_setg(errp, "Failed to set encryption key"); if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) {
goto error; error_setg(errp, "Failed to set encryption key");
} goto error;
}
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) { if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
error_setg(errp, "Failed to set decryption key"); error_setg(errp, "Failed to set decryption key");
goto error; goto error;
}
if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4,
&ctxt->state.aes.key_tweak.enc) != 0) {
error_setg(errp, "Failed to set encryption key");
goto error;
}
if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4,
&ctxt->state.aes.key_tweak.dec) != 0) {
error_setg(errp, "Failed to set decryption key");
goto error;
}
} else {
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.key.dec) != 0) {
error_setg(errp, "Failed to set decryption key");
goto error;
}
} }
ctxt->blocksize = AES_BLOCK_SIZE; ctxt->blocksize = AES_BLOCK_SIZE;
@ -356,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
cipher->alg = alg; cipher->alg = alg;
cipher->mode = mode; cipher->mode = mode;
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) { if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
goto error; goto error;
} }

View File

@ -19,6 +19,8 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "crypto/xts.h"
#include <gcrypt.h> #include <gcrypt.h>
@ -44,7 +46,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
struct QCryptoCipherGcrypt { struct QCryptoCipherGcrypt {
gcry_cipher_hd_t handle; gcry_cipher_hd_t handle;
gcry_cipher_hd_t tweakhandle;
size_t blocksize; size_t blocksize;
uint8_t *iv;
}; };
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
@ -59,6 +63,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
switch (mode) { switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_XTS:
gcrymode = GCRY_CIPHER_MODE_ECB; gcrymode = GCRY_CIPHER_MODE_ECB;
break; break;
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
@ -69,7 +74,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
return NULL; return NULL;
} }
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) { if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
return NULL; return NULL;
} }
@ -131,6 +136,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
gcry_strerror(err)); gcry_strerror(err));
goto error; goto error;
} }
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gcry_strerror(err));
goto error;
}
}
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) { if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
/* We're using standard DES cipher from gcrypt, so we need /* We're using standard DES cipher from gcrypt, so we need
@ -142,7 +155,23 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
g_free(rfbkey); g_free(rfbkey);
ctx->blocksize = 8; ctx->blocksize = 8;
} else { } else {
err = gcry_cipher_setkey(ctx->handle, key, nkey); if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
nkey /= 2;
err = gcry_cipher_setkey(ctx->handle, key, nkey);
if (err != 0) {
error_setg(errp, "Cannot set key: %s",
gcry_strerror(err));
goto error;
}
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
} else {
err = gcry_cipher_setkey(ctx->handle, key, nkey);
}
if (err != 0) {
error_setg(errp, "Cannot set key: %s",
gcry_strerror(err));
goto error;
}
switch (cipher->alg) { switch (cipher->alg) {
case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_192:
@ -161,10 +190,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
g_assert_not_reached(); g_assert_not_reached();
} }
} }
if (err != 0) {
error_setg(errp, "Cannot set key: %s", if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
gcry_strerror(err)); ctx->iv = g_new0(uint8_t, ctx->blocksize);
goto error;
} }
cipher->opaque = ctx; cipher->opaque = ctx;
@ -172,6 +200,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
error: error:
gcry_cipher_close(ctx->handle); gcry_cipher_close(ctx->handle);
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
gcry_cipher_close(ctx->tweakhandle);
}
g_free(ctx); g_free(ctx);
g_free(cipher); g_free(cipher);
return NULL; return NULL;
@ -186,11 +217,35 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
} }
ctx = cipher->opaque; ctx = cipher->opaque;
gcry_cipher_close(ctx->handle); gcry_cipher_close(ctx->handle);
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
gcry_cipher_close(ctx->tweakhandle);
}
g_free(ctx->iv);
g_free(ctx); g_free(ctx);
g_free(cipher); g_free(cipher);
} }
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);
}
int qcrypto_cipher_encrypt(QCryptoCipher *cipher, int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in, const void *in,
void *out, void *out,
@ -206,13 +261,20 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
return -1; return -1;
} }
err = gcry_cipher_encrypt(ctx->handle, if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
out, len, xts_encrypt(ctx->handle, ctx->tweakhandle,
in, len); qcrypto_gcrypt_xts_encrypt,
if (err != 0) { qcrypto_gcrypt_xts_decrypt,
error_setg(errp, "Cannot encrypt data: %s", ctx->iv, len, out, in);
gcry_strerror(err)); } else {
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; return 0;
@ -234,13 +296,20 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
return -1; return -1;
} }
err = gcry_cipher_decrypt(ctx->handle, if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
out, len, xts_decrypt(ctx->handle, ctx->tweakhandle,
in, len); qcrypto_gcrypt_xts_encrypt,
if (err != 0) { qcrypto_gcrypt_xts_decrypt,
error_setg(errp, "Cannot decrypt data: %s", ctx->iv, len, out, in);
gcry_strerror(err)); } else {
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; return 0;
@ -259,12 +328,16 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
return -1; return -1;
} }
gcry_cipher_reset(ctx->handle); if (ctx->iv) {
err = gcry_cipher_setiv(ctx->handle, iv, niv); memcpy(ctx->iv, iv, niv);
if (err != 0) { } else {
error_setg(errp, "Cannot set IV: %s", 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)); gcry_strerror(err));
return -1; return -1;
}
} }
return 0; return 0;

View File

@ -19,6 +19,8 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "crypto/xts.h"
#include <nettle/nettle-types.h> #include <nettle/nettle-types.h>
#include <nettle/aes.h> #include <nettle/aes.h>
#include <nettle/des.h> #include <nettle/des.h>
@ -111,9 +113,14 @@ static void twofish_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
typedef struct QCryptoCipherNettle QCryptoCipherNettle; typedef struct QCryptoCipherNettle QCryptoCipherNettle;
struct QCryptoCipherNettle { struct QCryptoCipherNettle {
/* Primary cipher context for all modes */
void *ctx; void *ctx;
/* Second cipher context for XTS mode only */
void *ctx_tweak;
/* Cipher callbacks for both contexts */
nettle_cipher_func *alg_encrypt; nettle_cipher_func *alg_encrypt;
nettle_cipher_func *alg_decrypt; nettle_cipher_func *alg_decrypt;
uint8_t *iv; uint8_t *iv;
size_t blocksize; size_t blocksize;
}; };
@ -151,13 +158,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
switch (mode) { switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
case QCRYPTO_CIPHER_MODE_XTS:
break; break;
default: default:
error_setg(errp, "Unsupported cipher mode %d", mode); error_setg(errp, "Unsupported cipher mode %d", mode);
return NULL; return NULL;
} }
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) { if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
return NULL; return NULL;
} }
@ -185,8 +193,25 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_AES_256: case QCRYPTO_CIPHER_ALG_AES_256:
ctx->ctx = g_new0(QCryptoNettleAES, 1); ctx->ctx = g_new0(QCryptoNettleAES, 1);
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc, nkey, key); if (mode == QCRYPTO_CIPHER_MODE_XTS) {
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec, nkey, key); ctx->ctx_tweak = g_new0(QCryptoNettleAES, 1);
nkey /= 2;
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
nkey, key);
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
nkey, key);
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->enc,
nkey, key + nkey);
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->dec,
nkey, key + nkey);
} else {
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
nkey, key);
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
nkey, key);
}
ctx->alg_encrypt = aes_encrypt_wrapper; ctx->alg_encrypt = aes_encrypt_wrapper;
ctx->alg_decrypt = aes_decrypt_wrapper; ctx->alg_decrypt = aes_decrypt_wrapper;
@ -197,7 +222,15 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_CAST5_128: case QCRYPTO_CIPHER_ALG_CAST5_128:
ctx->ctx = g_new0(struct cast128_ctx, 1); ctx->ctx = g_new0(struct cast128_ctx, 1);
cast5_set_key(ctx->ctx, nkey, key); if (mode == QCRYPTO_CIPHER_MODE_XTS) {
ctx->ctx_tweak = g_new0(struct cast128_ctx, 1);
nkey /= 2;
cast5_set_key(ctx->ctx, nkey, key);
cast5_set_key(ctx->ctx_tweak, nkey, key + nkey);
} else {
cast5_set_key(ctx->ctx, nkey, key);
}
ctx->alg_encrypt = cast128_encrypt_wrapper; ctx->alg_encrypt = cast128_encrypt_wrapper;
ctx->alg_decrypt = cast128_decrypt_wrapper; ctx->alg_decrypt = cast128_decrypt_wrapper;
@ -210,7 +243,15 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_SERPENT_256: case QCRYPTO_CIPHER_ALG_SERPENT_256:
ctx->ctx = g_new0(struct serpent_ctx, 1); ctx->ctx = g_new0(struct serpent_ctx, 1);
serpent_set_key(ctx->ctx, nkey, key); if (mode == QCRYPTO_CIPHER_MODE_XTS) {
ctx->ctx_tweak = g_new0(struct serpent_ctx, 1);
nkey /= 2;
serpent_set_key(ctx->ctx, nkey, key);
serpent_set_key(ctx->ctx_tweak, nkey, key + nkey);
} else {
serpent_set_key(ctx->ctx, nkey, key);
}
ctx->alg_encrypt = serpent_encrypt_wrapper; ctx->alg_encrypt = serpent_encrypt_wrapper;
ctx->alg_decrypt = serpent_decrypt_wrapper; ctx->alg_decrypt = serpent_decrypt_wrapper;
@ -223,7 +264,15 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_ALG_TWOFISH_256: case QCRYPTO_CIPHER_ALG_TWOFISH_256:
ctx->ctx = g_new0(struct twofish_ctx, 1); ctx->ctx = g_new0(struct twofish_ctx, 1);
twofish_set_key(ctx->ctx, nkey, key); if (mode == QCRYPTO_CIPHER_MODE_XTS) {
ctx->ctx_tweak = g_new0(struct twofish_ctx, 1);
nkey /= 2;
twofish_set_key(ctx->ctx, nkey, key);
twofish_set_key(ctx->ctx_tweak, nkey, key + nkey);
} else {
twofish_set_key(ctx->ctx, nkey, key);
}
ctx->alg_encrypt = twofish_encrypt_wrapper; ctx->alg_encrypt = twofish_encrypt_wrapper;
ctx->alg_decrypt = twofish_decrypt_wrapper; ctx->alg_decrypt = twofish_decrypt_wrapper;
@ -259,6 +308,7 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
ctx = cipher->opaque; ctx = cipher->opaque;
g_free(ctx->iv); g_free(ctx->iv);
g_free(ctx->ctx); g_free(ctx->ctx);
g_free(ctx->ctx_tweak);
g_free(ctx); g_free(ctx);
g_free(cipher); g_free(cipher);
} }
@ -289,6 +339,12 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
len, out, in); len, out, in);
break; break;
case QCRYPTO_CIPHER_MODE_XTS:
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
ctx->alg_encrypt, ctx->alg_encrypt,
ctx->iv, len, out, in);
break;
default: default:
error_setg(errp, "Unsupported cipher algorithm %d", error_setg(errp, "Unsupported cipher algorithm %d",
cipher->alg); cipher->alg);
@ -323,6 +379,17 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
len, out, in); len, out, in);
break; break;
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,
ctx->alg_encrypt, ctx->alg_decrypt,
ctx->iv, len, out, in);
break;
default: default:
error_setg(errp, "Unsupported cipher algorithm %d", error_setg(errp, "Unsupported cipher algorithm %d",
cipher->alg); cipher->alg);

View File

@ -53,6 +53,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = { static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
[QCRYPTO_CIPHER_MODE_ECB] = false, [QCRYPTO_CIPHER_MODE_ECB] = false,
[QCRYPTO_CIPHER_MODE_CBC] = true, [QCRYPTO_CIPHER_MODE_CBC] = true,
[QCRYPTO_CIPHER_MODE_XTS] = true,
}; };
@ -93,6 +94,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
static bool static bool
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
size_t nkey, size_t nkey,
Error **errp) Error **errp)
{ {
@ -102,10 +104,27 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
return false; return false;
} }
if (alg_key_len[alg] != nkey) { if (mode == QCRYPTO_CIPHER_MODE_XTS) {
error_setg(errp, "Cipher key length %zu should be %zu", if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
nkey, alg_key_len[alg]); error_setg(errp, "XTS mode not compatible with DES-RFB");
return false; return false;
}
if (nkey % 2) {
error_setg(errp, "XTS cipher key length should be a multiple of 2");
return false;
}
if (alg_key_len[alg] != (nkey / 2)) {
error_setg(errp, "Cipher key length %zu should be %zu",
nkey, alg_key_len[alg] * 2);
return false;
}
} else {
if (alg_key_len[alg] != nkey) {
error_setg(errp, "Cipher key length %zu should be %zu",
nkey, alg_key_len[alg]);
return false;
}
} }
return true; return true;
} }

View File

@ -84,11 +84,12 @@
# #
# @ecb: Electronic Code Book # @ecb: Electronic Code Book
# @cbc: Cipher Block Chaining # @cbc: Cipher Block Chaining
# @xts: XEX with tweaked code book and ciphertext stealing
# Since: 2.6 # Since: 2.6
## ##
{ 'enum': 'QCryptoCipherMode', { 'enum': 'QCryptoCipherMode',
'prefix': 'QCRYPTO_CIPHER_MODE', 'prefix': 'QCRYPTO_CIPHER_MODE',
'data': ['ecb', 'cbc']} 'data': ['ecb', 'cbc', 'xts']}
## ##

View File

@ -242,6 +242,134 @@ static QCryptoCipherTestData test_data[] = {
.plaintext = "90afe91bb288544f2c32dc239b2635e6", .plaintext = "90afe91bb288544f2c32dc239b2635e6",
.ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa", .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
}, },
{
/* #1 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-1",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"00000000000000000000000000000000"
"00000000000000000000000000000000",
.iv =
"00000000000000000000000000000000",
.plaintext =
"00000000000000000000000000000000"
"00000000000000000000000000000000",
.ciphertext =
"917cf69ebd68b2ec9b9fe9a3eadda692"
"cd43d2f59598ed858c02c2652fbf922e",
},
{
/* #2, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-2",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"11111111111111111111111111111111"
"22222222222222222222222222222222",
.iv =
"33333333330000000000000000000000",
.plaintext =
"44444444444444444444444444444444"
"44444444444444444444444444444444",
.ciphertext =
"c454185e6a16936e39334038acef838b"
"fb186fff7480adc4289382ecd6d394f0",
},
{
/* #5 from xts.7, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-3",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0"
"bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0",
.iv =
"9a785634120000000000000000000000",
.plaintext =
"44444444444444444444444444444444"
"44444444444444444444444444444444",
.ciphertext =
"b01f86f8edc1863706fa8a4253e34f28"
"af319de38334870f4dd1f94cbe9832f1",
},
{
/* #4, 32 byte key, 512 byte PTX */
.path = "/crypto/cipher/aes-xts-128-4",
.alg = QCRYPTO_CIPHER_ALG_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"27182818284590452353602874713526"
"31415926535897932384626433832795",
.iv =
"00000000000000000000000000000000",
.plaintext =
"000102030405060708090a0b0c0d0e0f"
"101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f"
"303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f"
"505152535455565758595a5b5c5d5e5f"
"606162636465666768696a6b6c6d6e6f"
"707172737475767778797a7b7c7d7e7f"
"808182838485868788898a8b8c8d8e8f"
"909192939495969798999a9b9c9d9e9f"
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
"000102030405060708090a0b0c0d0e0f"
"101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f"
"303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f"
"505152535455565758595a5b5c5d5e5f"
"606162636465666768696a6b6c6d6e6f"
"707172737475767778797a7b7c7d7e7f"
"808182838485868788898a8b8c8d8e8f"
"909192939495969798999a9b9c9d9e9f"
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
.ciphertext =
"27a7479befa1d476489f308cd4cfa6e2"
"a96e4bbe3208ff25287dd3819616e89c"
"c78cf7f5e543445f8333d8fa7f560000"
"05279fa5d8b5e4ad40e736ddb4d35412"
"328063fd2aab53e5ea1e0a9f332500a5"
"df9487d07a5c92cc512c8866c7e860ce"
"93fdf166a24912b422976146ae20ce84"
"6bb7dc9ba94a767aaef20c0d61ad0265"
"5ea92dc4c4e41a8952c651d33174be51"
"a10c421110e6d81588ede82103a252d8"
"a750e8768defffed9122810aaeb99f91"
"72af82b604dc4b8e51bcb08235a6f434"
"1332e4ca60482a4ba1a03b3e65008fc5"
"da76b70bf1690db4eae29c5f1badd03c"
"5ccf2a55d705ddcd86d449511ceb7ec3"
"0bf12b1fa35b913f9f747a8afd1b130e"
"94bff94effd01a91735ca1726acd0b19"
"7c4e5b03393697e126826fb6bbde8ecc"
"1e08298516e2c9ed03ff3c1b7860f6de"
"76d4cecd94c8119855ef5297ca67e9f3"
"e7ff72b1e99785ca0a7e7720c5b36dc6"
"d72cac9574c8cbbc2f801e23e56fd344"
"b07f22154beba0f08ce8891e643ed995"
"c94d9a69c9f1b5f499027a78572aeebd"
"74d20cc39881c213ee770b1010e4bea7"
"18846977ae119f7a023ab58cca0ad752"
"afe656bb3c17256a9f6e9bf19fdd5a38"
"fc82bbe872c5539edb609ef4f79c203e"
"bb140f2e583cb2ad15b4aa5b655016a8"
"449277dbd477ef2c8d6c017db738b18d"
"eb4a427d1923ce3ff262735779a418f2"
"0a282df920147beabe421ee5319d0568",
},
}; };
@ -328,7 +456,11 @@ static void test_cipher(const void *opaque)
blocksize = qcrypto_cipher_get_block_len(data->alg); blocksize = qcrypto_cipher_get_block_len(data->alg);
ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode); ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode);
g_assert_cmpint(keysize, ==, nkey); if (data->mode == QCRYPTO_CIPHER_MODE_XTS) {
g_assert_cmpint(keysize * 2, ==, nkey);
} else {
g_assert_cmpint(keysize, ==, nkey);
}
g_assert_cmpint(ivsize, ==, niv); g_assert_cmpint(ivsize, ==, niv);
if (niv) { if (niv) {
g_assert_cmpint(blocksize, ==, niv); g_assert_cmpint(blocksize, ==, niv);