mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-10-06 11:09:37 +00:00
Merge crypto patches 2018/12/12
- Fix documentation about default LUKS algorithms - Support for multi-threaded block crypto -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJcEO9QAAoJEL6G67QVEE/fkE0QAJXHxr3u9UtOE2IllTS/rxtD nmiH8B4gdTJ2GFdYxoyoQP8nParRh0QEWjDtiOLId8Wnt9BUtbEtd89OOQsPkqw7 EDyfvIBkT0ZfWVHrhayzfItM1UCkQzbUSehdq+unZA7eXU9E/bTC12kme97M9cIh VdQ2LE67A0hb5Bvv/o1gZcwtrK51h1PVVizhp8fKJh0owTV4VCZ5bbmXJSK0SdmW dZKstJzBZOQnDrqSBEDMWtNMASuPNnYxfSgB/tgeOwDd3qjjNB6LBH0REaDzpEGR WzwXzCinfr/KjdyN3OzEbkzuD7J/qySJNsarDe1aT0I+lm1KpjqLC6QRJ+cvXOyg tX/2Y5XPevKsHPzvrhcyuiOO67OR5Xa/D0c2imWJOM2dmeDK7xMUyjHGKt4ijCBL 4M/Y/zbWDagMJf6DUUA3h3Q7NeWHA7mpQUOh1xjc3TJzjp091Fe3xCwm13dF+gu+ JZ8hF982Yy5SsvVWXBXYLUTtOUdX8tTaMtxDwvzxNram11APbDxiDhruBZ71jV8x 4C1ZmSPDuLGiVylB6T8dUuNoKRdHScIBs42bxUITbBvI8F0lvQBE0LkXqZJMXEY9 IcLAeGvcZTjvx6lsO39anT44UbIWOLWmLfebMQlRItEknb3HdJ0rDuTIHDaRSzKh OimAIGc7B6BjuIcczBDP =bOs1 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange/tags/qcrypto-next-pull-request' into staging Merge crypto patches 2018/12/12 - Fix documentation about default LUKS algorithms - Support for multi-threaded block crypto # gpg: Signature made Wed 12 Dec 2018 11:21:52 GMT # gpg: using RSA key BE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange/tags/qcrypto-next-pull-request: crypto: support multiple threads accessing one QCryptoBlock crypto/block: introduce qcrypto_block_*crypt_helper functions crypto/block: rename qcrypto_block_*crypt_helper crypto/block: refactor qcrypto_block_*crypt_helper functions crypto/block-luks: fix memory leak in qcrypto_block_luks_create crypto: Fix defaults in QCryptoBlockCreateOptionsLUKS Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d8d5fefd86
|
@ -229,6 +229,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
||||||
block_crypto_read_func,
|
block_crypto_read_func,
|
||||||
bs,
|
bs,
|
||||||
cflags,
|
cflags,
|
||||||
|
1,
|
||||||
errp);
|
errp);
|
||||||
|
|
||||||
if (!crypto->block) {
|
if (!crypto->block) {
|
||||||
|
|
|
@ -213,7 +213,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
||||||
}
|
}
|
||||||
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
|
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
|
||||||
NULL, NULL, cflags, errp);
|
NULL, NULL, cflags, 1, errp);
|
||||||
if (!s->crypto) {
|
if (!s->crypto) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -294,7 +294,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||||
}
|
}
|
||||||
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
|
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
|
||||||
qcow2_crypto_hdr_read_func,
|
qcow2_crypto_hdr_read_func,
|
||||||
bs, cflags, errp);
|
bs, cflags, 1, errp);
|
||||||
if (!s->crypto) {
|
if (!s->crypto) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1445,7 +1445,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||||
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
||||||
}
|
}
|
||||||
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
|
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
|
||||||
NULL, NULL, cflags, errp);
|
NULL, NULL, cflags, 1, errp);
|
||||||
if (!s->crypto) {
|
if (!s->crypto) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -504,14 +504,14 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
|
||||||
* to reset the encryption cipher every time the master
|
* to reset the encryption cipher every time the master
|
||||||
* key crosses a sector boundary.
|
* key crosses a sector boundary.
|
||||||
*/
|
*/
|
||||||
if (qcrypto_block_decrypt_helper(cipher,
|
if (qcrypto_block_cipher_decrypt_helper(cipher,
|
||||||
niv,
|
niv,
|
||||||
ivgen,
|
ivgen,
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
0,
|
0,
|
||||||
splitkey,
|
splitkey,
|
||||||
splitkeylen,
|
splitkeylen,
|
||||||
errp) < 0) {
|
errp) < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,6 +636,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
||||||
QCryptoBlockReadFunc readfunc,
|
QCryptoBlockReadFunc readfunc,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
QCryptoBlockLUKS *luks;
|
QCryptoBlockLUKS *luks;
|
||||||
|
@ -836,11 +837,10 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
block->cipher = qcrypto_cipher_new(cipheralg,
|
ret = qcrypto_block_init_cipher(block, cipheralg, ciphermode,
|
||||||
ciphermode,
|
masterkey, masterkeylen, n_threads,
|
||||||
masterkey, masterkeylen,
|
errp);
|
||||||
errp);
|
if (ret < 0) {
|
||||||
if (!block->cipher) {
|
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -863,7 +863,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
g_free(masterkey);
|
g_free(masterkey);
|
||||||
qcrypto_cipher_free(block->cipher);
|
qcrypto_block_free_cipher(block);
|
||||||
qcrypto_ivgen_free(block->ivgen);
|
qcrypto_ivgen_free(block->ivgen);
|
||||||
g_free(luks);
|
g_free(luks);
|
||||||
g_free(password);
|
g_free(password);
|
||||||
|
@ -1030,11 +1030,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||||
|
|
||||||
|
|
||||||
/* Setup the block device payload encryption objects */
|
/* Setup the block device payload encryption objects */
|
||||||
block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg,
|
if (qcrypto_block_init_cipher(block, luks_opts.cipher_alg,
|
||||||
luks_opts.cipher_mode,
|
luks_opts.cipher_mode, masterkey,
|
||||||
masterkey, luks->header.key_bytes,
|
luks->header.key_bytes, 1, errp) < 0) {
|
||||||
errp);
|
|
||||||
if (!block->cipher) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,12 +1217,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||||
|
|
||||||
/* Now we encrypt the split master key with the key generated
|
/* Now we encrypt the split master key with the key generated
|
||||||
* from the user's password, before storing it */
|
* from the user's password, before storing it */
|
||||||
if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen,
|
if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen,
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
0,
|
0,
|
||||||
splitkey,
|
splitkey,
|
||||||
splitkeylen,
|
splitkeylen,
|
||||||
errp) < 0) {
|
errp) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1341,6 +1339,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||||
qcrypto_ivgen_free(ivgen);
|
qcrypto_ivgen_free(ivgen);
|
||||||
qcrypto_cipher_free(cipher);
|
qcrypto_cipher_free(cipher);
|
||||||
|
|
||||||
|
qcrypto_block_free_cipher(block);
|
||||||
|
qcrypto_ivgen_free(block->ivgen);
|
||||||
|
|
||||||
g_free(luks);
|
g_free(luks);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1406,8 +1407,7 @@ qcrypto_block_luks_decrypt(QCryptoBlock *block,
|
||||||
{
|
{
|
||||||
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
return qcrypto_block_decrypt_helper(block->cipher,
|
return qcrypto_block_decrypt_helper(block,
|
||||||
block->niv, block->ivgen,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
offset, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
@ -1422,8 +1422,7 @@ qcrypto_block_luks_encrypt(QCryptoBlock *block,
|
||||||
{
|
{
|
||||||
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
return qcrypto_block_encrypt_helper(block->cipher,
|
return qcrypto_block_encrypt_helper(block,
|
||||||
block->niv, block->ivgen,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
offset, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
|
||||||
static int
|
static int
|
||||||
qcrypto_block_qcow_init(QCryptoBlock *block,
|
qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||||
const char *keysecret,
|
const char *keysecret,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
char *password;
|
char *password;
|
||||||
|
@ -71,11 +72,11 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
QCRYPTO_CIPHER_MODE_CBC,
|
QCRYPTO_CIPHER_MODE_CBC,
|
||||||
keybuf, G_N_ELEMENTS(keybuf),
|
keybuf, G_N_ELEMENTS(keybuf),
|
||||||
errp);
|
n_threads, errp);
|
||||||
if (!block->cipher) {
|
if (ret < 0) {
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +87,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
qcrypto_cipher_free(block->cipher);
|
qcrypto_block_free_cipher(block);
|
||||||
qcrypto_ivgen_free(block->ivgen);
|
qcrypto_ivgen_free(block->ivgen);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -99,6 +100,7 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
|
||||||
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
|
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
|
||||||
void *opaque G_GNUC_UNUSED,
|
void *opaque G_GNUC_UNUSED,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
|
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
|
||||||
|
@ -112,8 +114,8 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
|
||||||
optprefix ? optprefix : "");
|
optprefix ? optprefix : "");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return qcrypto_block_qcow_init(block,
|
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret,
|
||||||
options->u.qcow.key_secret, errp);
|
n_threads, errp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +135,7 @@ qcrypto_block_qcow_create(QCryptoBlock *block,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* QCow2 has no special header, since everything is hardwired */
|
/* QCow2 has no special header, since everything is hardwired */
|
||||||
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
|
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, 1, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,8 +154,7 @@ qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||||
{
|
{
|
||||||
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
return qcrypto_block_decrypt_helper(block->cipher,
|
return qcrypto_block_decrypt_helper(block,
|
||||||
block->niv, block->ivgen,
|
|
||||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||||
offset, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
@ -168,8 +169,7 @@ qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||||
{
|
{
|
||||||
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
return qcrypto_block_encrypt_helper(block->cipher,
|
return qcrypto_block_encrypt_helper(block,
|
||||||
block->niv, block->ivgen,
|
|
||||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||||
offset, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
233
crypto/block.c
233
crypto/block.c
|
@ -52,6 +52,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||||
QCryptoBlockReadFunc readfunc,
|
QCryptoBlockReadFunc readfunc,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||||
|
@ -69,11 +70,14 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||||
block->driver = qcrypto_block_drivers[options->format];
|
block->driver = qcrypto_block_drivers[options->format];
|
||||||
|
|
||||||
if (block->driver->open(block, options, optprefix,
|
if (block->driver->open(block, options, optprefix,
|
||||||
readfunc, opaque, flags, errp) < 0) {
|
readfunc, opaque, flags, n_threads, errp) < 0)
|
||||||
|
{
|
||||||
g_free(block);
|
g_free(block);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_mutex_init(&block->mutex);
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +109,8 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_mutex_init(&block->mutex);
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,12 +154,97 @@ int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||||
|
|
||||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
|
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
|
||||||
{
|
{
|
||||||
return block->cipher;
|
/* Ciphers should be accessed through pop/push method to be thread-safe.
|
||||||
|
* Better, they should not be accessed externally at all (note, that
|
||||||
|
* pop/push are static functions)
|
||||||
|
* This function is used only in test with one thread (it's safe to skip
|
||||||
|
* pop/push interface), so it's enough to assert it here:
|
||||||
|
*/
|
||||||
|
assert(block->n_ciphers <= 1);
|
||||||
|
return block->ciphers ? block->ciphers[0] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
|
||||||
|
{
|
||||||
|
QCryptoCipher *cipher;
|
||||||
|
|
||||||
|
qemu_mutex_lock(&block->mutex);
|
||||||
|
|
||||||
|
assert(block->n_free_ciphers > 0);
|
||||||
|
block->n_free_ciphers--;
|
||||||
|
cipher = block->ciphers[block->n_free_ciphers];
|
||||||
|
|
||||||
|
qemu_mutex_unlock(&block->mutex);
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qcrypto_block_push_cipher(QCryptoBlock *block,
|
||||||
|
QCryptoCipher *cipher)
|
||||||
|
{
|
||||||
|
qemu_mutex_lock(&block->mutex);
|
||||||
|
|
||||||
|
assert(block->n_free_ciphers < block->n_ciphers);
|
||||||
|
block->ciphers[block->n_free_ciphers] = cipher;
|
||||||
|
block->n_free_ciphers++;
|
||||||
|
|
||||||
|
qemu_mutex_unlock(&block->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_block_init_cipher(QCryptoBlock *block,
|
||||||
|
QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
size_t n_threads, Error **errp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
|
||||||
|
|
||||||
|
block->ciphers = g_new0(QCryptoCipher *, n_threads);
|
||||||
|
|
||||||
|
for (i = 0; i < n_threads; i++) {
|
||||||
|
block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
|
||||||
|
if (!block->ciphers[i]) {
|
||||||
|
qcrypto_block_free_cipher(block);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
block->n_ciphers++;
|
||||||
|
block->n_free_ciphers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qcrypto_block_free_cipher(QCryptoBlock *block)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!block->ciphers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(block->n_ciphers == block->n_free_ciphers);
|
||||||
|
|
||||||
|
for (i = 0; i < block->n_ciphers; i++) {
|
||||||
|
qcrypto_cipher_free(block->ciphers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(block->ciphers);
|
||||||
|
block->ciphers = NULL;
|
||||||
|
block->n_ciphers = block->n_free_ciphers = 0;
|
||||||
|
}
|
||||||
|
|
||||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
|
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
|
||||||
{
|
{
|
||||||
|
/* ivgen should be accessed under mutex. However, this function is used only
|
||||||
|
* in test with one thread, so it's enough to assert it here:
|
||||||
|
*/
|
||||||
|
assert(block->n_ciphers <= 1);
|
||||||
return block->ivgen;
|
return block->ivgen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,20 +275,29 @@ void qcrypto_block_free(QCryptoBlock *block)
|
||||||
|
|
||||||
block->driver->cleanup(block);
|
block->driver->cleanup(block);
|
||||||
|
|
||||||
qcrypto_cipher_free(block->cipher);
|
qcrypto_block_free_cipher(block);
|
||||||
qcrypto_ivgen_free(block->ivgen);
|
qcrypto_ivgen_free(block->ivgen);
|
||||||
|
qemu_mutex_destroy(&block->mutex);
|
||||||
g_free(block);
|
g_free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
|
||||||
size_t niv,
|
const void *in,
|
||||||
QCryptoIVGen *ivgen,
|
void *out,
|
||||||
int sectorsize,
|
size_t len,
|
||||||
uint64_t offset,
|
Error **errp);
|
||||||
uint8_t *buf,
|
|
||||||
size_t len,
|
static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
|
||||||
Error **errp)
|
size_t niv,
|
||||||
|
QCryptoIVGen *ivgen,
|
||||||
|
QemuMutex *ivgen_mutex,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
QCryptoCipherEncDecFunc func,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *iv;
|
uint8_t *iv;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
@ -211,10 +311,15 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
if (niv) {
|
if (niv) {
|
||||||
if (qcrypto_ivgen_calculate(ivgen,
|
if (ivgen_mutex) {
|
||||||
startsector,
|
qemu_mutex_lock(ivgen_mutex);
|
||||||
iv, niv,
|
}
|
||||||
errp) < 0) {
|
ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
|
||||||
|
if (ivgen_mutex) {
|
||||||
|
qemu_mutex_unlock(ivgen_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +331,7 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||||
}
|
}
|
||||||
|
|
||||||
nbytes = len > sectorsize ? sectorsize : len;
|
nbytes = len > sectorsize ? sectorsize : len;
|
||||||
if (qcrypto_cipher_decrypt(cipher, buf, buf,
|
if (func(cipher, buf, buf, nbytes, errp) < 0) {
|
||||||
nbytes, errp) < 0) {
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,54 +347,69 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
|
||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
|
||||||
|
offset, buf, len,
|
||||||
|
qcrypto_cipher_decrypt, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
|
||||||
|
size_t niv,
|
||||||
|
QCryptoIVGen *ivgen,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
|
||||||
|
offset, buf, len,
|
||||||
|
qcrypto_cipher_encrypt, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_block_decrypt_helper(QCryptoBlock *block,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *iv;
|
int ret;
|
||||||
int ret = -1;
|
QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
|
||||||
uint64_t startsector = offset / sectorsize;
|
|
||||||
|
|
||||||
assert(QEMU_IS_ALIGNED(offset, sectorsize));
|
ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
|
||||||
assert(QEMU_IS_ALIGNED(len, sectorsize));
|
&block->mutex, sectorsize, offset, buf,
|
||||||
|
len, qcrypto_cipher_decrypt, errp);
|
||||||
|
|
||||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
qcrypto_block_push_cipher(block, cipher);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcrypto_block_encrypt_helper(QCryptoBlock *block,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
|
||||||
|
|
||||||
|
ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
|
||||||
|
&block->mutex, sectorsize, offset, buf,
|
||||||
|
len, qcrypto_cipher_encrypt, errp);
|
||||||
|
|
||||||
|
qcrypto_block_push_cipher(block, cipher);
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
size_t nbytes;
|
|
||||||
if (niv) {
|
|
||||||
if (qcrypto_ivgen_calculate(ivgen,
|
|
||||||
startsector,
|
|
||||||
iv, niv,
|
|
||||||
errp) < 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qcrypto_cipher_setiv(cipher,
|
|
||||||
iv, niv,
|
|
||||||
errp) < 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = len > sectorsize ? sectorsize : len;
|
|
||||||
if (qcrypto_cipher_encrypt(cipher, buf, buf,
|
|
||||||
nbytes, errp) < 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
startsector++;
|
|
||||||
buf += nbytes;
|
|
||||||
len -= nbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
|
||||||
g_free(iv);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define QCRYPTO_BLOCKPRIV_H
|
#define QCRYPTO_BLOCKPRIV_H
|
||||||
|
|
||||||
#include "crypto/block.h"
|
#include "crypto/block.h"
|
||||||
|
#include "qemu/thread.h"
|
||||||
|
|
||||||
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
|
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
|
||||||
|
|
||||||
|
@ -31,8 +32,12 @@ struct QCryptoBlock {
|
||||||
const QCryptoBlockDriver *driver;
|
const QCryptoBlockDriver *driver;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
QCryptoCipher *cipher;
|
QCryptoCipher **ciphers;
|
||||||
|
size_t n_ciphers;
|
||||||
|
size_t n_free_ciphers;
|
||||||
QCryptoIVGen *ivgen;
|
QCryptoIVGen *ivgen;
|
||||||
|
QemuMutex mutex;
|
||||||
|
|
||||||
QCryptoHashAlgorithm kdfhash;
|
QCryptoHashAlgorithm kdfhash;
|
||||||
size_t niv;
|
size_t niv;
|
||||||
uint64_t payload_offset; /* In bytes */
|
uint64_t payload_offset; /* In bytes */
|
||||||
|
@ -46,6 +51,7 @@ struct QCryptoBlockDriver {
|
||||||
QCryptoBlockReadFunc readfunc,
|
QCryptoBlockReadFunc readfunc,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
int (*create)(QCryptoBlock *block,
|
int (*create)(QCryptoBlock *block,
|
||||||
|
@ -78,22 +84,44 @@ struct QCryptoBlockDriver {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
|
||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
|
||||||
|
size_t niv,
|
||||||
|
QCryptoIVGen *ivgen,
|
||||||
|
int sectorsize,
|
||||||
|
uint64_t offset,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
int qcrypto_block_decrypt_helper(QCryptoBlock *block,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
int qcrypto_block_encrypt_helper(QCryptoBlock *block,
|
||||||
size_t niv,
|
|
||||||
QCryptoIVGen *ivgen,
|
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
|
int qcrypto_block_init_cipher(QCryptoBlock *block,
|
||||||
|
QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
size_t n_threads, Error **errp);
|
||||||
|
|
||||||
|
void qcrypto_block_free_cipher(QCryptoBlock *block);
|
||||||
|
|
||||||
#endif /* QCRYPTO_BLOCKPRIV_H */
|
#endif /* QCRYPTO_BLOCKPRIV_H */
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef enum {
|
||||||
* @readfunc: callback for reading data from the volume
|
* @readfunc: callback for reading data from the volume
|
||||||
* @opaque: data to pass to @readfunc
|
* @opaque: data to pass to @readfunc
|
||||||
* @flags: bitmask of QCryptoBlockOpenFlags values
|
* @flags: bitmask of QCryptoBlockOpenFlags values
|
||||||
|
* @n_threads: allow concurrent I/O from up to @n_threads threads
|
||||||
* @errp: pointer to a NULL-initialized error object
|
* @errp: pointer to a NULL-initialized error object
|
||||||
*
|
*
|
||||||
* Create a new block encryption object for an existing
|
* Create a new block encryption object for an existing
|
||||||
|
@ -107,6 +108,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||||
QCryptoBlockReadFunc readfunc,
|
QCryptoBlockReadFunc readfunc,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
size_t n_threads,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -181,11 +181,11 @@
|
||||||
# The options that apply to LUKS encryption format initialization
|
# The options that apply to LUKS encryption format initialization
|
||||||
#
|
#
|
||||||
# @cipher-alg: the cipher algorithm for data encryption
|
# @cipher-alg: the cipher algorithm for data encryption
|
||||||
# Currently defaults to 'aes'.
|
# Currently defaults to 'aes-256'.
|
||||||
# @cipher-mode: the cipher mode for data encryption
|
# @cipher-mode: the cipher mode for data encryption
|
||||||
# Currently defaults to 'cbc'
|
# Currently defaults to 'xts'
|
||||||
# @ivgen-alg: the initialization vector generator
|
# @ivgen-alg: the initialization vector generator
|
||||||
# Currently defaults to 'essiv'
|
# Currently defaults to 'plain64'
|
||||||
# @ivgen-hash-alg: the initialization vector generator hash
|
# @ivgen-hash-alg: the initialization vector generator hash
|
||||||
# Currently defaults to 'sha256'
|
# Currently defaults to 'sha256'
|
||||||
# @hash-alg: the master key hash algorithm
|
# @hash-alg: the master key hash algorithm
|
||||||
|
|
|
@ -305,6 +305,7 @@ static void test_block(gconstpointer opaque)
|
||||||
test_block_read_func,
|
test_block_read_func,
|
||||||
&header,
|
&header,
|
||||||
0,
|
0,
|
||||||
|
1,
|
||||||
NULL);
|
NULL);
|
||||||
g_assert(blk == NULL);
|
g_assert(blk == NULL);
|
||||||
|
|
||||||
|
@ -313,6 +314,7 @@ static void test_block(gconstpointer opaque)
|
||||||
test_block_read_func,
|
test_block_read_func,
|
||||||
&header,
|
&header,
|
||||||
QCRYPTO_BLOCK_OPEN_NO_IO,
|
QCRYPTO_BLOCK_OPEN_NO_IO,
|
||||||
|
1,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
|
||||||
g_assert(qcrypto_block_get_cipher(blk) == NULL);
|
g_assert(qcrypto_block_get_cipher(blk) == NULL);
|
||||||
|
@ -327,6 +329,7 @@ static void test_block(gconstpointer opaque)
|
||||||
test_block_read_func,
|
test_block_read_func,
|
||||||
&header,
|
&header,
|
||||||
0,
|
0,
|
||||||
|
1,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
g_assert(blk);
|
g_assert(blk);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue