Browse Source
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>pull/7/merge
14 changed files with 873 additions and 0 deletions
@ -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, |
|||
}; |
|||
|
|||
@ -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__ */ |
|||
@ -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, |
|||
}; |
|||
|
|||
@ -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__ */ |
|||
@ -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, |
|||
}; |
|||
|
|||
@ -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__ */ |
|||
@ -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); |
|||
} |
|||
@ -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__ */ |
|||
@ -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__ */ |
|||
@ -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