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:
parent
37788f253a
commit
cb730894ae
@ -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
118
crypto/ivgen-essiv.c
Normal 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 *)§or, 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
28
crypto/ivgen-essiv.h
Normal 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
59
crypto/ivgen-plain.c
Normal 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
28
crypto/ivgen-plain.h
Normal 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
59
crypto/ivgen-plain64.c
Normal 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, §or, 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
28
crypto/ivgen-plain64.h
Normal 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
99
crypto/ivgen.c
Normal 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
49
crypto/ivgenpriv.h
Normal 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
206
include/crypto/ivgen.h
Normal 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__ */
|
@ -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
1
tests/.gitignore
vendored
@ -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
|
||||
|
@ -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
173
tests/test-crypto-ivgen.c
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user