crypto: add support for generating initialization vectors

There are a number of different algorithms that can be used
to generate initialization vectors for disk encryption. This
introduces a simple internal QCryptoBlockIV object to provide
a consistent internal API to the different algorithms. The
initially implemented algorithms are 'plain', 'plain64' and
'essiv', each matching the same named algorithm provided
by the Linux kernel dm-crypt driver.

Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2015-10-15 12:35:28 +01:00
parent 37788f253a
commit cb730894ae
14 changed files with 873 additions and 0 deletions

View file

@ -13,6 +13,10 @@ crypto-obj-$(if $(CONFIG_GCRYPT),n,$(CONFIG_GNUTLS_RND)) += random-gnutls.o
crypto-obj-y += pbkdf.o
crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o
crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT_KDF)) += pbkdf-gcrypt.o
crypto-obj-y += ivgen.o
crypto-obj-y += ivgen-essiv.o
crypto-obj-y += ivgen-plain.o
crypto-obj-y += ivgen-plain64.o
# Let the userspace emulators avoid linking gnutls/etc
crypto-aes-obj-y = aes.o

118
crypto/ivgen-essiv.c Normal file
View file

@ -0,0 +1,118 @@
/*
* QEMU Crypto block IV generator - essiv
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "crypto/ivgen-essiv.h"
typedef struct QCryptoIVGenESSIV QCryptoIVGenESSIV;
struct QCryptoIVGenESSIV {
QCryptoCipher *cipher;
};
static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
const uint8_t *key, size_t nkey,
Error **errp)
{
uint8_t *salt;
size_t nhash;
size_t nsalt;
QCryptoIVGenESSIV *essiv = g_new0(QCryptoIVGenESSIV, 1);
/* Not necessarily the same as nkey */
nsalt = qcrypto_cipher_get_key_len(ivgen->cipher);
nhash = qcrypto_hash_digest_len(ivgen->hash);
/* Salt must be larger of hash size or key size */
salt = g_new0(uint8_t, MAX(nhash, nsalt));
if (qcrypto_hash_bytes(ivgen->hash, (const gchar *)key, nkey,
&salt, &nhash,
errp) < 0) {
g_free(essiv);
return -1;
}
/* Now potentially truncate salt to match cipher key len */
essiv->cipher = qcrypto_cipher_new(ivgen->cipher,
QCRYPTO_CIPHER_MODE_ECB,
salt, MIN(nhash, nsalt),
errp);
if (!essiv->cipher) {
g_free(essiv);
g_free(salt);
return -1;
}
g_free(salt);
ivgen->private = essiv;
return 0;
}
static int qcrypto_ivgen_essiv_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoIVGenESSIV *essiv = ivgen->private;
size_t ndata = qcrypto_cipher_get_block_len(ivgen->cipher);
uint8_t *data = g_new(uint8_t, ndata);
sector = cpu_to_le64(sector);
memcpy(data, (uint8_t *)&sector, ndata);
if (sizeof(sector) < ndata) {
memset(data + sizeof(sector), 0, ndata - sizeof(sector));
}
if (qcrypto_cipher_encrypt(essiv->cipher,
data,
data,
ndata,
errp) < 0) {
g_free(data);
return -1;
}
if (ndata > niv) {
ndata = niv;
}
memcpy(iv, data, ndata);
if (ndata < niv) {
memset(iv + ndata, 0, niv - ndata);
}
g_free(data);
return 0;
}
static void qcrypto_ivgen_essiv_cleanup(QCryptoIVGen *ivgen)
{
QCryptoIVGenESSIV *essiv = ivgen->private;
qcrypto_cipher_free(essiv->cipher);
g_free(essiv);
}
struct QCryptoIVGenDriver qcrypto_ivgen_essiv = {
.init = qcrypto_ivgen_essiv_init,
.calculate = qcrypto_ivgen_essiv_calculate,
.cleanup = qcrypto_ivgen_essiv_cleanup,
};

28
crypto/ivgen-essiv.h Normal file
View file

@ -0,0 +1,28 @@
/*
* QEMU Crypto block IV generator - essiv
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "crypto/ivgenpriv.h"
#ifndef QCRYPTO_IVGEN_ESSIV_H__
#define QCRYPTO_IVGEN_ESSIV_H__
extern struct QCryptoIVGenDriver qcrypto_ivgen_essiv;
#endif /* QCRYPTO_IVGEN_ESSIV_H__ */

59
crypto/ivgen-plain.c Normal file
View file

@ -0,0 +1,59 @@
/*
* QEMU Crypto block IV generator - plain
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "crypto/ivgen-plain.h"
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
const uint8_t *key, size_t nkey,
Error **errp)
{
return 0;
}
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp)
{
size_t ivprefix;
uint32_t shortsector = cpu_to_le32((sector & 0xffffffff));
ivprefix = sizeof(shortsector);
if (ivprefix > niv) {
ivprefix = niv;
}
memcpy(iv, &shortsector, ivprefix);
if (ivprefix < niv) {
memset(iv + ivprefix, 0, niv - ivprefix);
}
return 0;
}
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
{
}
struct QCryptoIVGenDriver qcrypto_ivgen_plain = {
.init = qcrypto_ivgen_plain_init,
.calculate = qcrypto_ivgen_plain_calculate,
.cleanup = qcrypto_ivgen_plain_cleanup,
};

28
crypto/ivgen-plain.h Normal file
View file

@ -0,0 +1,28 @@
/*
* QEMU Crypto block IV generator - plain
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "crypto/ivgenpriv.h"
#ifndef QCRYPTO_IVGEN_PLAIN_H__
#define QCRYPTO_IVGEN_PLAIN_H__
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain;
#endif /* QCRYPTO_IVGEN_PLAIN_H__ */

59
crypto/ivgen-plain64.c Normal file
View file

@ -0,0 +1,59 @@
/*
* QEMU Crypto block IV generator - plain
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "crypto/ivgen-plain.h"
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
const uint8_t *key, size_t nkey,
Error **errp)
{
return 0;
}
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp)
{
size_t ivprefix;
ivprefix = sizeof(sector);
sector = cpu_to_le64(sector);
if (ivprefix > niv) {
ivprefix = niv;
}
memcpy(iv, &sector, ivprefix);
if (ivprefix < niv) {
memset(iv + ivprefix, 0, niv - ivprefix);
}
return 0;
}
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
{
}
struct QCryptoIVGenDriver qcrypto_ivgen_plain64 = {
.init = qcrypto_ivgen_plain_init,
.calculate = qcrypto_ivgen_plain_calculate,
.cleanup = qcrypto_ivgen_plain_cleanup,
};

28
crypto/ivgen-plain64.h Normal file
View file

@ -0,0 +1,28 @@
/*
* QEMU Crypto block IV generator - plain64
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "crypto/ivgenpriv.h"
#ifndef QCRYPTO_IVGEN_PLAIN64_H__
#define QCRYPTO_IVGEN_PLAIN64_H__
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain64;
#endif /* QCRYPTO_IVGEN_PLAIN64_H__ */

99
crypto/ivgen.c Normal file
View file

@ -0,0 +1,99 @@
/*
* QEMU Crypto block IV generator
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "crypto/ivgenpriv.h"
#include "crypto/ivgen-plain.h"
#include "crypto/ivgen-plain64.h"
#include "crypto/ivgen-essiv.h"
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
QCryptoCipherAlgorithm cipheralg,
QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoIVGen *ivgen = g_new0(QCryptoIVGen, 1);
ivgen->algorithm = alg;
ivgen->cipher = cipheralg;
ivgen->hash = hash;
switch (alg) {
case QCRYPTO_IVGEN_ALG_PLAIN:
ivgen->driver = &qcrypto_ivgen_plain;
break;
case QCRYPTO_IVGEN_ALG_PLAIN64:
ivgen->driver = &qcrypto_ivgen_plain64;
break;
case QCRYPTO_IVGEN_ALG_ESSIV:
ivgen->driver = &qcrypto_ivgen_essiv;
break;
default:
error_setg(errp, "Unknown block IV generator algorithm %d", alg);
g_free(ivgen);
return NULL;
}
if (ivgen->driver->init(ivgen, key, nkey, errp) < 0) {
g_free(ivgen);
return NULL;
}
return ivgen;
}
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp)
{
return ivgen->driver->calculate(ivgen, sector, iv, niv, errp);
}
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen)
{
return ivgen->algorithm;
}
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen)
{
return ivgen->cipher;
}
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen)
{
return ivgen->hash;
}
void qcrypto_ivgen_free(QCryptoIVGen *ivgen)
{
if (!ivgen) {
return;
}
ivgen->driver->cleanup(ivgen);
g_free(ivgen);
}

49
crypto/ivgenpriv.h Normal file
View file

@ -0,0 +1,49 @@
/*
* QEMU Crypto block IV generator
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_IVGEN_PRIV_H__
#define QCRYPTO_IVGEN_PRIV_H__
#include "crypto/ivgen.h"
typedef struct QCryptoIVGenDriver QCryptoIVGenDriver;
struct QCryptoIVGenDriver {
int (*init)(QCryptoIVGen *ivgen,
const uint8_t *key, size_t nkey,
Error **errp);
int (*calculate)(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp);
void (*cleanup)(QCryptoIVGen *ivgen);
};
struct QCryptoIVGen {
QCryptoIVGenDriver *driver;
void *private;
QCryptoIVGenAlgorithm algorithm;
QCryptoCipherAlgorithm cipher;
QCryptoHashAlgorithm hash;
};
#endif /* QCRYPTO_IVGEN_PRIV_H__ */

206
include/crypto/ivgen.h Normal file
View file

@ -0,0 +1,206 @@
/*
* QEMU Crypto block IV generator
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_IVGEN_H__
#define QCRYPTO_IVGEN_H__
#include "crypto/cipher.h"
#include "crypto/hash.h"
/**
* This module provides a framework for generating initialization
* vectors for block encryption schemes using chained cipher modes
* CBC. The principle is that each disk sector is assigned a unique
* initialization vector for use for encryption of data in that
* sector.
*
* <example>
* <title>Encrypting block data with initialiation vectors</title>
* <programlisting>
* uint8_t *data = ....data to encrypt...
* size_t ndata = XXX;
* uint8_t *key = ....some encryption key...
* size_t nkey = XXX;
* uint8_t *iv;
* size_t niv;
* size_t sector = 0;
*
* g_assert((ndata % 512) == 0);
*
* QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV,
* QCRYPTO_CIPHER_ALG_AES_128,
* QCRYPTO_HASH_ALG_SHA256,
* key, nkey, errp);
* if (!ivgen) {
* return -1;
* }
*
* QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, nkey, errp);
* if (!cipher) {
* goto error;
* }
*
* niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
* QCRYPTO_CIPHER_MODE_CBC);
* iv = g_new0(uint8_t, niv);
*
*
* while (ndata) {
* if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) {
* goto error;
* }
* if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) {
* goto error;
* }
* if (qcrypto_cipher_encrypt(cipher,
* data + (sector * 512),
* data + (sector * 512),
* 512, errp) < 0) {
* goto error;
* }
* sector++;
* ndata -= 512;
* }
*
* g_free(iv);
* qcrypto_ivgen_free(ivgen);
* qcrypto_cipher_free(cipher);
* return 0;
*
*error:
* g_free(iv);
* qcrypto_ivgen_free(ivgen);
* qcrypto_cipher_free(cipher);
* return -1;
* </programlisting>
* </example>
*/
typedef struct QCryptoIVGen QCryptoIVGen;
/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */
/**
* qcrypto_ivgen_new:
* @alg: the initialization vector generation algorithm
* @cipheralg: the cipher algorithm or 0
* @hash: the hash algorithm or 0
* @key: the encryption key or NULL
* @nkey: the size of @key in bytes
*
* Create a new initialization vector generator that uses
* the algorithm @alg. Whether the remaining parameters
* are required or not depends on the choice of @alg
* requested.
*
* - QCRYPTO_IVGEN_ALG_PLAIN
*
* The IVs are generated by the 32-bit truncated sector
* number. This should never be used for block devices
* that are larger than 2^32 sectors in size.
* All the other parameters are unused.
*
* - QCRYPTO_IVGEN_ALG_PLAIN64
*
* The IVs are generated by the 64-bit sector number.
* All the other parameters are unused.
*
* - QCRYPTO_IVGEN_ALG_ESSIV:
*
* The IVs are generated by encrypting the 64-bit sector
* number with a hash of an encryption key. The @cipheralg,
* @hash, @key and @nkey parameters are all required.
*
* Returns: a new IV generator, or NULL on error
*/
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
QCryptoCipherAlgorithm cipheralg,
QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
Error **errp);
/**
* qcrypto_ivgen_calculate:
* @ivgen: the IV generator object
* @sector: the 64-bit sector number
* @iv: a pre-allocated buffer to hold the generated IV
* @niv: the number of bytes in @iv
* @errp: pointer to a NULL-initialized error object
*
* Calculate a new initialiation vector for the data
* to be stored in sector @sector. The IV will be
* written into the buffer @iv of size @niv.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp);
/**
* qcrypto_ivgen_get_algorithm:
* @ivgen: the IV generator object
*
* Get the algorithm used by this IV generator
*
* Returns: the IV generator algorithm
*/
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_get_cipher:
* @ivgen: the IV generator object
*
* Get the cipher algorithm used by this IV generator (if
* applicable)
*
* Returns: the cipher algorithm
*/
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_get_hash:
* @ivgen: the IV generator object
*
* Get the hash algorithm used by this IV generator (if
* applicable)
*
* Returns: the hash algorithm
*/
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_free:
* @ivgen: the IV generator object
*
* Release all resources associated with @ivgen, or a no-op
* if @ivgen is NULL
*/
void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
#endif /* QCRYPTO_IVGEN_H__ */

View file

@ -78,3 +78,22 @@
{ 'enum': 'QCryptoCipherMode',
'prefix': 'QCRYPTO_CIPHER_MODE',
'data': ['ecb', 'cbc']}
##
# QCryptoIVGenAlgorithm:
#
# The supported algorithms for generating initialization
# vectors for full disk encryption. The 'plain' generator
# should not be used for disks with sector numbers larger
# than 2^32, except where compatibility with pre-existing
# Linux dm-crypt volumes is required.
#
# @plain: 64-bit sector number truncated to 32-bits
# @plain64: 64-bit sector number
# @essiv: 64-bit sector number encrypted with a hash of the encryption key
# Since: 2.6
##
{ 'enum': 'QCryptoIVGenAlgorithm',
'prefix': 'QCRYPTO_IVGEN_ALG',
'data': ['plain', 'plain64', 'essiv']}

1
tests/.gitignore vendored
View file

@ -14,6 +14,7 @@ test-blockjob-txn
test-coroutine
test-crypto-cipher
test-crypto-hash
test-crypto-ivgen
test-crypto-pbkdf
test-crypto-secret
test-crypto-tlscredsx509

View file

@ -93,6 +93,7 @@ check-unit-y += tests/test-io-channel-command$(EXESUF)
check-unit-y += tests/test-io-channel-buffer$(EXESUF)
check-unit-y += tests/test-base64$(EXESUF)
check-unit-$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT_KDF)) += tests/test-crypto-pbkdf$(EXESUF)
check-unit-y += tests/test-crypto-ivgen$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@ -498,6 +499,7 @@ tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \
tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \
tests/io-channel-helpers.o $(test-io-obj-y)
tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y)
tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y)
libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o

173
tests/test-crypto-ivgen.c Normal file
View file

@ -0,0 +1,173 @@
/*
* QEMU Crypto IV generator algorithms
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "crypto/ivgen.h"
struct QCryptoIVGenTestData {
const char *path;
uint64_t sector;
QCryptoIVGenAlgorithm ivalg;
QCryptoHashAlgorithm hashalg;
QCryptoCipherAlgorithm cipheralg;
const uint8_t *key;
size_t nkey;
const uint8_t *iv;
size_t niv;
} test_data[] = {
/* Small */
{
"/crypto/ivgen/plain/1",
.sector = 0x1,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* Big ! */
{
"/crypto/ivgen/plain/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* Truncation */
{
"/crypto/ivgen/plain/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* Small */
{
"/crypto/ivgen/plain64/1",
.sector = 0x1,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* Big ! */
{
"/crypto/ivgen/plain64/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* No Truncation */
{
"/crypto/ivgen/plain64/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x4c\x3d\x2e\x1f"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
},
/* Small */
{
"/crypto/ivgen/essiv/1",
.sector = 0x1,
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
.hashalg = QCRYPTO_HASH_ALG_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
.iv = (const uint8_t *)"\xd4\x83\x71\xb2\xa1\x94\x53\x88"
"\x1c\x7a\x2d\06\x2d\x0b\x65\x46",
.niv = 16,
},
/* Big ! */
{
"/crypto/ivgen/essiv/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
.hashalg = QCRYPTO_HASH_ALG_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
.iv = (const uint8_t *)"\x5d\x36\x09\x5d\xc6\x9e\x5e\xe9"
"\xe3\x02\x8d\xd8\x7a\x3d\xe7\x8f",
.niv = 16,
},
/* No Truncation */
{
"/crypto/ivgen/essiv/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
.hashalg = QCRYPTO_HASH_ALG_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
.iv = (const uint8_t *)"\x58\xbb\x81\x94\x51\x83\x23\x23"
"\x7a\x08\x93\xa9\xdc\xd2\xd9\xab",
.niv = 16,
},
};
static void test_ivgen(const void *opaque)
{
const struct QCryptoIVGenTestData *data = opaque;
uint8_t *iv = g_new0(uint8_t, data->niv);
QCryptoIVGen *ivgen = qcrypto_ivgen_new(
data->ivalg,
data->cipheralg,
data->hashalg,
data->key,
data->nkey,
&error_abort);
qcrypto_ivgen_calculate(ivgen,
data->sector,
iv,
data->niv,
&error_abort);
g_assert(memcmp(iv, data->iv, data->niv) == 0);
qcrypto_ivgen_free(ivgen);
g_free(iv);
}
int main(int argc, char **argv)
{
size_t i;
g_test_init(&argc, &argv, NULL);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
if (test_data[i].ivalg == QCRYPTO_IVGEN_ALG_ESSIV &&
!qcrypto_hash_supports(test_data[i].hashalg)) {
continue;
}
g_test_add_data_func(test_data[i].path,
&(test_data[i]),
test_ivgen);
}
return g_test_run();
}