mirror of https://github.com/xemu-project/xemu.git
Merge QCrypto 2016/03/17 v3
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJW6uCUAAoJEL6G67QVEE/f1gkQAIoFBhCRzBI2OGh1vyG/Tf9e WkROnvcY57QAmpcoQ2uim+5hI+7yIIlXMkG4LhI2EGlBWpHfSKGuAb4BGJ8TMmaJ Jv+9nt4eIq7XW6/fE4+wJm/DNdjv1spLR22JiUhNUXQfuY3uN9a1hDlnG6qLj3CF qMBI+fJsi4SkOpymeIqvmPjegVl192h6OqIAvU4tl0XGTiODL5zGqHJGEa3BgKi1 Ad4fUFf+zKRXA31xb5UmX9aC3a+bjG7/iZP9cWT+i0vIlSa9Iz2CT6ocnLS62BTF aHHsxYLakUeYvNH9t9oqlptJYEXxB4jNJmaCzvKPlzME3eM2bJbeCL3EUmC+mH92 k6e5AY30bs91W56gtpTX67RbvuVPHApaqRNWbMgRmsO9cHX5YdFhiB+5g9129xoe 9LhaOxasVcy2Srq1HIt9VEmt3PLgCWs3Tr/uPWfWP0pOo4P+Y1C9hBZuwj7/RTeY 2hjbRUYjS/Hz9if+QhIMiXGH2v+ngkhnkBKK3wOjPBqmMz0oKaMCKlz3O2/N8Spz x4x7yVv+up1u9NZGwxHXBrnkXJrOuWjBNIwVFNggJo1MtiiGdYCMIwcVtCjIcYuY xPkTQC0fk0HVv148LmA3AQgWmXQMJf3PI0BXt/81vbJervb174zeRz5WP5IOQzrS dgWbuJl3t1ehPmiJvASL =7xJW -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/berrange/tags/pull-qcrypto-2016-03-17-3' into staging Merge QCrypto 2016/03/17 v3 # gpg: Signature made Thu 17 Mar 2016 16:51:32 GMT using RSA key ID 15104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" * remotes/berrange/tags/pull-qcrypto-2016-03-17-3: crypto: implement the LUKS block encryption format crypto: add block encryption framework crypto: wire up XTS mode for cipher APIs crypto: refactor code for dealing with AES cipher crypto: import an implementation of the XTS cipher mode crypto: add support for the twofish cipher algorithm crypto: add support for the serpent cipher algorithm crypto: add support for the cast5-128 cipher algorithm crypto: skip testing of unsupported cipher algorithms crypto: add support for anti-forensic split algorithm crypto: add support for generating initialization vectors crypto: add support for PBKDF2 algorithm crypto: add cryptographic random byte source Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
879c26fb9f
|
@ -1,6 +1,6 @@
|
|||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
stub-obj-y = stubs/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
||||
|
||||
|
|
|
@ -306,8 +306,10 @@ gtkabi=""
|
|||
gtk_gl="no"
|
||||
gnutls=""
|
||||
gnutls_hash=""
|
||||
gnutls_rnd=""
|
||||
nettle=""
|
||||
gcrypt=""
|
||||
gcrypt_kdf="no"
|
||||
vte=""
|
||||
virglrenderer=""
|
||||
tpm="yes"
|
||||
|
@ -2201,6 +2203,13 @@ if test "$gnutls" != "no"; then
|
|||
gnutls_hash="no"
|
||||
fi
|
||||
|
||||
# gnutls_rnd requires >= 2.11.0
|
||||
if $pkg_config --exists "gnutls >= 2.11.0"; then
|
||||
gnutls_rnd="yes"
|
||||
else
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
if $pkg_config --exists 'gnutls >= 3.0'; then
|
||||
gnutls_gcrypt=no
|
||||
gnutls_nettle=yes
|
||||
|
@ -2228,9 +2237,11 @@ if test "$gnutls" != "no"; then
|
|||
else
|
||||
gnutls="no"
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
else
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
|
||||
|
@ -2292,6 +2303,19 @@ if test "$gcrypt" != "no"; then
|
|||
if test -z "$nettle"; then
|
||||
nettle="no"
|
||||
fi
|
||||
|
||||
cat > $TMPC << EOF
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_kdf_derive(NULL, 0, GCRY_KDF_PBKDF2,
|
||||
GCRY_MD_SHA256,
|
||||
NULL, 0, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||
gcrypt_kdf=yes
|
||||
fi
|
||||
else
|
||||
if test "$gcrypt" = "yes"; then
|
||||
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||
|
@ -4714,7 +4738,9 @@ echo "GTK support $gtk"
|
|||
echo "GTK GL support $gtk_gl"
|
||||
echo "GNUTLS support $gnutls"
|
||||
echo "GNUTLS hash $gnutls_hash"
|
||||
echo "GNUTLS rnd $gnutls_rnd"
|
||||
echo "libgcrypt $gcrypt"
|
||||
echo "libgcrypt kdf $gcrypt_kdf"
|
||||
if test "$nettle" = "yes"; then
|
||||
echo "nettle $nettle ($nettle_version)"
|
||||
else
|
||||
|
@ -5092,8 +5118,14 @@ fi
|
|||
if test "$gnutls_hash" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gnutls_rnd" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gcrypt" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
||||
if test "$gcrypt_kdf" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$nettle" = "yes" ; then
|
||||
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||||
|
|
|
@ -8,6 +8,23 @@ crypto-obj-y += tlscredsanon.o
|
|||
crypto-obj-y += tlscredsx509.o
|
||||
crypto-obj-y += tlssession.o
|
||||
crypto-obj-y += secret.o
|
||||
crypto-obj-$(CONFIG_GCRYPT) += random-gcrypt.o
|
||||
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
|
||||
crypto-obj-y += afsplit.o
|
||||
crypto-obj-y += xts.o
|
||||
crypto-obj-y += block.o
|
||||
crypto-obj-y += block-qcow.o
|
||||
crypto-obj-y += block-luks.o
|
||||
|
||||
# Let the userspace emulators avoid linking gnutls/etc
|
||||
crypto-aes-obj-y = aes.o
|
||||
|
||||
stub-obj-y += random-stub.o
|
||||
stub-obj-y += pbkdf-stub.o
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* QEMU Crypto anti forensic information splitter
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* Derived from cryptsetup package lib/luks1/af.c
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU 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/afsplit.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
|
||||
static void qcrypto_afsplit_xor(size_t blocklen,
|
||||
const uint8_t *in1,
|
||||
const uint8_t *in2,
|
||||
uint8_t *out)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < blocklen; i++) {
|
||||
out[i] = in1[i] ^ in2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint8_t *block,
|
||||
Error **errp)
|
||||
{
|
||||
size_t digestlen = qcrypto_hash_digest_len(hash);
|
||||
|
||||
size_t hashcount = blocklen / digestlen;
|
||||
size_t finallen = blocklen % digestlen;
|
||||
uint32_t i;
|
||||
|
||||
if (finallen) {
|
||||
hashcount++;
|
||||
} else {
|
||||
finallen = digestlen;
|
||||
}
|
||||
|
||||
for (i = 0; i < hashcount; i++) {
|
||||
uint8_t *out = NULL;
|
||||
size_t outlen = 0;
|
||||
uint32_t iv = cpu_to_be32(i);
|
||||
struct iovec in[] = {
|
||||
{ .iov_base = &iv,
|
||||
.iov_len = sizeof(iv) },
|
||||
{ .iov_base = block + (i * digestlen),
|
||||
.iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
|
||||
};
|
||||
|
||||
if (qcrypto_hash_bytesv(hash,
|
||||
in,
|
||||
G_N_ELEMENTS(in),
|
||||
&out, &outlen,
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(outlen == digestlen);
|
||||
memcpy(block + (i * digestlen), out,
|
||||
(i == (hashcount - 1)) ? finallen : digestlen);
|
||||
g_free(out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
out + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in,
|
||||
block,
|
||||
out + (i * blocklen));
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
out);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption LUKS format
|
||||
*
|
||||
* 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_BLOCK_LUKS_H__
|
||||
#define QCRYPTO_BLOCK_LUKS_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_luks;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_LUKS_H__ */
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that the block encryption implemented in this file is broken
|
||||
* by design. This exists only to allow data to be liberated from
|
||||
* existing qcow[2] images and should not be used in any new areas.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/secret.h"
|
||||
|
||||
#define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
|
||||
|
||||
|
||||
static bool
|
||||
qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
|
||||
size_t buf_size G_GNUC_UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||
const char *keysecret,
|
||||
Error **errp)
|
||||
{
|
||||
char *password;
|
||||
int ret;
|
||||
uint8_t keybuf[16];
|
||||
int len;
|
||||
|
||||
memset(keybuf, 0, 16);
|
||||
|
||||
password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
|
||||
if (!password) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(password);
|
||||
memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
|
||||
g_free(password);
|
||||
|
||||
block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC);
|
||||
block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
0, 0, NULL, 0, errp);
|
||||
if (!block->ivgen) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC,
|
||||
keybuf, G_N_ELEMENTS(keybuf),
|
||||
errp);
|
||||
if (!block->cipher) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->payload_offset = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_open(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
|
||||
return 0;
|
||||
} else {
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp,
|
||||
"Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
return qcrypto_block_qcow_init(block,
|
||||
options->u.qcow.key_secret, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_create(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
|
||||
QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp, "Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
/* QCow2 has no special header, since everything is hardwired */
|
||||
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_block_qcow_cleanup(QCryptoBlock *block)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_decrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_encrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
const QCryptoBlockDriver qcrypto_block_driver_qcow = {
|
||||
.open = qcrypto_block_qcow_open,
|
||||
.create = qcrypto_block_qcow_create,
|
||||
.cleanup = qcrypto_block_qcow_cleanup,
|
||||
.decrypt = qcrypto_block_qcow_decrypt,
|
||||
.encrypt = qcrypto_block_qcow_encrypt,
|
||||
.has_format = qcrypto_block_qcow_has_format,
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* 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_BLOCK_QCOW_H__
|
||||
#define QCRYPTO_BLOCK_QCOW_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_qcow;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_QCOW_H__ */
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* 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/blockpriv.h"
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/block-luks.h"
|
||||
|
||||
static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
|
||||
[Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
|
||||
[Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
|
||||
};
|
||||
|
||||
|
||||
bool qcrypto_block_has_format(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
const QCryptoBlockDriver *driver;
|
||||
|
||||
if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[format]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
driver = qcrypto_block_drivers[format];
|
||||
|
||||
return driver->has_format(buf, len);
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->open(block, options,
|
||||
readfunc, opaque, flags, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->create(block, options, initfunc,
|
||||
writefunc, opaque, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->decrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->encrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
|
||||
{
|
||||
return block->cipher;
|
||||
}
|
||||
|
||||
|
||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
|
||||
{
|
||||
return block->ivgen;
|
||||
}
|
||||
|
||||
|
||||
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
|
||||
{
|
||||
return block->kdfhash;
|
||||
}
|
||||
|
||||
|
||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
|
||||
{
|
||||
return block->payload_offset;
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_block_free(QCryptoBlock *block)
|
||||
{
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->driver->cleanup(block);
|
||||
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
g_free(block);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
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_decrypt(cipher, buf, buf,
|
||||
nbytes, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
startsector++;
|
||||
buf += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
g_free(iv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* 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_BLOCK_PRIV_H__
|
||||
#define QCRYPTO_BLOCK_PRIV_H__
|
||||
|
||||
#include "crypto/block.h"
|
||||
|
||||
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
|
||||
|
||||
struct QCryptoBlock {
|
||||
QCryptoBlockFormat format;
|
||||
|
||||
const QCryptoBlockDriver *driver;
|
||||
void *opaque;
|
||||
|
||||
QCryptoCipher *cipher;
|
||||
QCryptoIVGen *ivgen;
|
||||
QCryptoHashAlgorithm kdfhash;
|
||||
size_t niv;
|
||||
uint64_t payload_offset; /* In bytes */
|
||||
};
|
||||
|
||||
struct QCryptoBlockDriver {
|
||||
int (*open)(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp);
|
||||
|
||||
int (*create)(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
void (*cleanup)(QCryptoBlock *block);
|
||||
|
||||
int (*encrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
int (*decrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
bool (*has_format)(const uint8_t *buf,
|
||||
size_t buflen);
|
||||
};
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_PRIV_H__ */
|
|
@ -21,11 +21,17 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/desrfb.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
|
||||
struct QCryptoCipherBuiltinAESContext {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||
struct QCryptoCipherBuiltinAES {
|
||||
AES_KEY encrypt_key;
|
||||
AES_KEY decrypt_key;
|
||||
QCryptoCipherBuiltinAESContext key;
|
||||
QCryptoCipherBuiltinAESContext key_tweak;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||
|
@ -67,6 +73,82 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
|
|||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
|
@ -75,29 +157,26 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
|||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.encrypt_key,
|
||||
&ctxt->state.aes.key.enc,
|
||||
ctxt->state.aes.iv, 1);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -112,29 +191,26 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
|||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.decrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.decrypt_key,
|
||||
&ctxt->state.aes.key.dec,
|
||||
ctxt->state.aes.iv, 0);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_decrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -166,21 +242,46 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
|||
QCryptoCipherBuiltin *ctxt;
|
||||
|
||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
|
||||
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ctxt->blocksize = AES_BLOCK_SIZE;
|
||||
|
@ -322,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
cipher->alg = alg;
|
||||
cipher->mode = mode;
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
|
||||
|
@ -29,6 +31,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
|||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -38,7 +46,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
|||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||
struct QCryptoCipherGcrypt {
|
||||
gcry_cipher_hd_t handle;
|
||||
gcry_cipher_hd_t tweakhandle;
|
||||
size_t blocksize;
|
||||
uint8_t *iv;
|
||||
};
|
||||
|
||||
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
@ -53,6 +63,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
|
@ -63,7 +74,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -84,6 +95,30 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
gcryalg = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
gcryalg = GCRY_CIPHER_CAST5;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
gcryalg = GCRY_CIPHER_SERPENT128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
gcryalg = GCRY_CIPHER_SERPENT192;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
gcryalg = GCRY_CIPHER_SERPENT256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
return NULL;
|
||||
|
@ -101,6 +136,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot initialize cipher: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
/* We're using standard DES cipher from gcrypt, so we need
|
||||
|
@ -112,13 +155,44 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
g_free(rfbkey);
|
||||
ctx->blocksize = 8;
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
ctx->blocksize = 16;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
nkey /= 2;
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
switch (cipher->alg) {
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->blocksize = 16;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->blocksize = 8;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
}
|
||||
|
||||
cipher->opaque = ctx;
|
||||
|
@ -126,6 +200,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
|
||||
error:
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
return NULL;
|
||||
|
@ -140,11 +217,35 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
|||
}
|
||||
ctx = cipher->opaque;
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
|
@ -160,13 +261,20 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
|||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -188,13 +296,20 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
|||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -213,12 +328,16 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
|||
return -1;
|
||||
}
|
||||
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
if (ctx->iv) {
|
||||
memcpy(ctx->iv, iv, niv);
|
||||
} else {
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -19,10 +19,15 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <nettle/nettle-types.h>
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/des.h>
|
||||
#include <nettle/cbc.h>
|
||||
#include <nettle/cast128.h>
|
||||
#include <nettle/serpent.h>
|
||||
#include <nettle/twofish.h>
|
||||
|
||||
#if CONFIG_NETTLE_VERSION_MAJOR < 3
|
||||
typedef nettle_crypt_func nettle_cipher_func;
|
||||
|
@ -39,16 +44,23 @@ static nettle_cipher_func aes_decrypt_wrapper;
|
|||
static nettle_cipher_func des_encrypt_wrapper;
|
||||
static nettle_cipher_func des_decrypt_wrapper;
|
||||
|
||||
typedef struct QCryptoNettleAES {
|
||||
struct aes_ctx enc;
|
||||
struct aes_ctx dec;
|
||||
} QCryptoNettleAES;
|
||||
|
||||
static void aes_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_encrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_encrypt(&aesctx->enc, length, dst, src);
|
||||
}
|
||||
|
||||
static void aes_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_decrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_decrypt(&aesctx->dec, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
|
@ -63,12 +75,52 @@ static void des_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
|||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
|
||||
struct QCryptoCipherNettle {
|
||||
void *ctx_encrypt;
|
||||
void *ctx_decrypt;
|
||||
/* Primary cipher context for all modes */
|
||||
void *ctx;
|
||||
/* Second cipher context for XTS mode only */
|
||||
void *ctx_tweak;
|
||||
/* Cipher callbacks for both contexts */
|
||||
nettle_cipher_func *alg_encrypt;
|
||||
nettle_cipher_func *alg_decrypt;
|
||||
|
||||
uint8_t *iv;
|
||||
size_t blocksize;
|
||||
};
|
||||
|
@ -80,6 +132,13 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
|||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -99,13 +158,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -117,10 +177,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
|
||||
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
|
||||
ctx->ctx = g_new0(struct des_ctx, 1);
|
||||
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||
des_set_key(ctx->ctx_encrypt, rfbkey);
|
||||
des_set_key(ctx->ctx, rfbkey);
|
||||
g_free(rfbkey);
|
||||
|
||||
ctx->alg_encrypt = des_encrypt_wrapper;
|
||||
|
@ -132,17 +191,95 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
|
||||
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
nkey /= 2;
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->enc,
|
||||
nkey, key + nkey);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->dec,
|
||||
nkey, key + nkey);
|
||||
} else {
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = aes_encrypt_wrapper;
|
||||
ctx->alg_decrypt = aes_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = AES_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->ctx = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
cast5_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = cast128_encrypt_wrapper;
|
||||
ctx->alg_decrypt = cast128_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = CAST128_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
ctx->ctx = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
serpent_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = serpent_encrypt_wrapper;
|
||||
ctx->alg_decrypt = serpent_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = SERPENT_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->ctx = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
twofish_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = twofish_encrypt_wrapper;
|
||||
ctx->alg_decrypt = twofish_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = TWOFISH_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
goto error;
|
||||
|
@ -170,8 +307,8 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
|||
|
||||
ctx = cipher->opaque;
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx->ctx_encrypt);
|
||||
g_free(ctx->ctx_decrypt);
|
||||
g_free(ctx->ctx);
|
||||
g_free(ctx->ctx_tweak);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
|
@ -193,14 +330,21 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
|||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
|
||||
ctx->alg_encrypt(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
|
||||
cbc_encrypt(ctx->ctx, ctx->alg_encrypt,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt, ctx->alg_encrypt,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
|
@ -226,15 +370,26 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
|||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
len, out, in);
|
||||
ctx->alg_decrypt(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
ctx->alg_decrypt, ctx->blocksize, ctx->iv,
|
||||
cbc_decrypt(ctx->ctx, ctx->alg_decrypt,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp, "Block size must be %d not %zu",
|
||||
XTS_BLOCK_SIZE, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt, ctx->alg_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
|
|
|
@ -27,6 +27,13 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
|||
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
|
||||
};
|
||||
|
||||
static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
|
@ -34,11 +41,19 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
|||
[QCRYPTO_CIPHER_ALG_AES_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
|
||||
};
|
||||
|
||||
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
||||
[QCRYPTO_CIPHER_MODE_CBC] = true,
|
||||
[QCRYPTO_CIPHER_MODE_XTS] = true,
|
||||
};
|
||||
|
||||
|
||||
|
@ -79,6 +94,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
|
|||
|
||||
static bool
|
||||
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -88,10 +104,27 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
error_setg(errp, "XTS mode not compatible with DES-RFB");
|
||||
return false;
|
||||
}
|
||||
if (nkey % 2) {
|
||||
error_setg(errp, "XTS cipher key length should be a multiple of 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != (nkey / 2)) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg] * 2);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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,68 @@
|
|||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* 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/pbkdf.h"
|
||||
#include "gcrypt.h"
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_MD5:
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (hash >= G_N_ELEMENTS(hash_map) ||
|
||||
hash_map[hash] == GCRY_MD_NONE) {
|
||||
error_setg(errp, "Unexpected hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_kdf_derive(key, nkey, GCRY_KDF_PBKDF2,
|
||||
hash_map[hash],
|
||||
salt, nsalt, iterations,
|
||||
nout, out);
|
||||
if (ret != 0) {
|
||||
error_setg(errp, "Cannot derive password: %s",
|
||||
gcry_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* 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/pbkdf.h"
|
||||
#include "nettle/pbkdf2.h"
|
||||
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
pbkdf2_hmac_sha1(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
pbkdf2_hmac_sha256(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"PBKDF does not support hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* 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/pbkdf.h"
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash G_GNUC_UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
|
||||
const uint8_t *key G_GNUC_UNUSED,
|
||||
size_t nkey G_GNUC_UNUSED,
|
||||
const uint8_t *salt G_GNUC_UNUSED,
|
||||
size_t nsalt G_GNUC_UNUSED,
|
||||
unsigned int iterations G_GNUC_UNUSED,
|
||||
uint8_t *out G_GNUC_UNUSED,
|
||||
size_t nout G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"No crypto library supporting PBKDF in this build");
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* 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/pbkdf.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
|
||||
static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
|
||||
Error **errp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FILETIME creation_time, exit_time, kernel_time, user_time;
|
||||
ULARGE_INTEGER thread_time;
|
||||
|
||||
if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time,
|
||||
&kernel_time, &user_time)) {
|
||||
error_setg(errp, "Unable to get thread CPU usage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread_time.LowPart = user_time.dwLowDateTime;
|
||||
thread_time.HighPart = user_time.dwHighDateTime;
|
||||
|
||||
/* QuadPart is units of 100ns and we want ms as unit */
|
||||
*val_ms = thread_time.QuadPart / 10000ll;
|
||||
return 0;
|
||||
#elif defined(RUSAGE_THREAD)
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_THREAD, &ru) < 0) {
|
||||
error_setg_errno(errp, errno, "Unable to get thread CPU usage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*val_ms = ((ru.ru_utime.tv_sec * 1000ll) +
|
||||
(ru.ru_utime.tv_usec / 1000));
|
||||
return 0;
|
||||
#else
|
||||
*val_ms = 0;
|
||||
error_setg(errp, "Unable to calculate thread CPU usage on this platform");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t out[32];
|
||||
long long int iterations = (1 << 15);
|
||||
unsigned long long delta_ms, start_ms, end_ms;
|
||||
|
||||
while (1) {
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2(hash,
|
||||
key, nkey,
|
||||
salt, nsalt,
|
||||
iterations,
|
||||
out, sizeof(out),
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
delta_ms = end_ms - start_ms;
|
||||
|
||||
if (delta_ms > 500) {
|
||||
break;
|
||||
} else if (delta_ms < 100) {
|
||||
iterations = iterations * 10;
|
||||
} else {
|
||||
iterations = (iterations * 1000 / delta_ms);
|
||||
}
|
||||
}
|
||||
|
||||
iterations = iterations * 1000 / delta_ms;
|
||||
|
||||
if (iterations > INT32_MAX) {
|
||||
error_setg(errp, "Iterations %lld too large for a 32-bit int",
|
||||
iterations);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return iterations;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* 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/random.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
gcry_randomize(buf, buflen, GCRY_STRONG_RANDOM);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* 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/random.h"
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gnutls_rnd(GNUTLS_RND_RANDOM, buf, buflen);
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot get random bytes: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* 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/random.h"
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
|
||||
size_t buflen G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "No random byte source provided in this build");
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
static void xts_mult_x(uint8_t *I)
|
||||
{
|
||||
int x;
|
||||
uint8_t t, tt;
|
||||
|
||||
for (x = t = 0; x < 16; x++) {
|
||||
tt = I[x] >> 7;
|
||||
I[x] = ((I[x] << 1) | t) & 0xFF;
|
||||
t = tt;
|
||||
}
|
||||
if (tt) {
|
||||
I[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xts_tweak_uncrypt:
|
||||
* @param ctxt: the cipher context
|
||||
* @param func: the cipher function
|
||||
* @src: buffer providing the cipher text of XTS_BLOCK_SIZE bytes
|
||||
* @dst: buffer to output the plain text of XTS_BLOCK_SIZE bytes
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
*
|
||||
* Decrypt data with a tweak
|
||||
*/
|
||||
static void xts_tweak_decrypt(const void *ctx,
|
||||
xts_cipher_func *func,
|
||||
const uint8_t *src,
|
||||
uint8_t *dst,
|
||||
uint8_t *iv)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
/* tweak encrypt block i */
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = src[x] ^ iv[x];
|
||||
}
|
||||
|
||||
func(ctx, XTS_BLOCK_SIZE, dst, dst);
|
||||
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = dst[x] ^ iv[x];
|
||||
}
|
||||
|
||||
/* LFSR the tweak */
|
||||
xts_mult_x(iv);
|
||||
}
|
||||
|
||||
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE];
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv);
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
xts_tweak_decrypt(datactx, decfunc, src, dst, T);
|
||||
|
||||
src += XTS_BLOCK_SIZE;
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
memcpy(CC, T, XTS_BLOCK_SIZE);
|
||||
xts_mult_x(CC);
|
||||
|
||||
/* PP = tweak decrypt block m-1 */
|
||||
xts_tweak_decrypt(datactx, decfunc, src, PP, CC);
|
||||
|
||||
/* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
|
||||
for (i = 0; i < mo; i++) {
|
||||
CC[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = PP[i];
|
||||
}
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
CC[i] = PP[i];
|
||||
}
|
||||
|
||||
/* Pm-1 = Tweak uncrypt CC */
|
||||
xts_tweak_decrypt(datactx, decfunc, CC, dst, T);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xts_tweak_crypt:
|
||||
* @param ctxt: the cipher context
|
||||
* @param func: the cipher function
|
||||
* @src: buffer providing the plain text of XTS_BLOCK_SIZE bytes
|
||||
* @dst: buffer to output the cipher text of XTS_BLOCK_SIZE bytes
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
*
|
||||
* Encrypt data with a tweak
|
||||
*/
|
||||
static void xts_tweak_encrypt(const void *ctx,
|
||||
xts_cipher_func *func,
|
||||
const uint8_t *src,
|
||||
uint8_t *dst,
|
||||
uint8_t *iv)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
/* tweak encrypt block i */
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = src[x] ^ iv[x];
|
||||
}
|
||||
|
||||
func(ctx, XTS_BLOCK_SIZE, dst, dst);
|
||||
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = dst[x] ^ iv[x];
|
||||
}
|
||||
|
||||
/* LFSR the tweak */
|
||||
xts_mult_x(iv);
|
||||
}
|
||||
|
||||
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE];
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv);
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
xts_tweak_encrypt(datactx, encfunc, src, dst, T);
|
||||
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
src += XTS_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
/* CC = tweak encrypt block m-1 */
|
||||
xts_tweak_encrypt(datactx, encfunc, src, CC, T);
|
||||
|
||||
/* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
|
||||
for (i = 0; i < mo; i++) {
|
||||
PP[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = CC[i];
|
||||
}
|
||||
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
PP[i] = CC[i];
|
||||
}
|
||||
|
||||
/* Cm-1 = Tweak encrypt PP */
|
||||
xts_tweak_encrypt(datactx, encfunc, PP, dst, T);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T);
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* QEMU Crypto anti forensic information splitter
|
||||
*
|
||||
* 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 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_AFSPLIT_H__
|
||||
#define QCRYPTO_AFSPLIT_H__
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/**
|
||||
* This module implements the anti-forensic splitter that is specified
|
||||
* as part of the LUKS format:
|
||||
*
|
||||
* http://clemens.endorphin.org/cryptography
|
||||
* http://clemens.endorphin.org/TKS1-draft.pdf
|
||||
*
|
||||
* The core idea is to take a short piece of data (key material)
|
||||
* and process it to expand it to a much larger piece of data.
|
||||
* The expansion process is reversible, to obtain the original
|
||||
* short data. The key property of the expansion is that if any
|
||||
* byte in the larger data set is changed / missing, it should be
|
||||
* impossible to recreate the original short data.
|
||||
*
|
||||
* <example>
|
||||
* <title>Creating a large split key for storage</title>
|
||||
* <programlisting>
|
||||
* size_t nkey = 32;
|
||||
* uint32_t stripes = 32768; // To produce a 1 MB split key
|
||||
* uint8_t *masterkey = ....a 32-byte AES key...
|
||||
* uint8_t *splitkey;
|
||||
*
|
||||
* splitkey = g_new0(uint8_t, nkey * stripes);
|
||||
*
|
||||
* if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALG_SHA256,
|
||||
* nkey, stripes,
|
||||
* masterkey, splitkey, errp) < 0) {
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* ...store splitkey somewhere...
|
||||
*
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* <example>
|
||||
* <title>Retrieving a master key from storage</title>
|
||||
* <programlisting>
|
||||
* size_t nkey = 32;
|
||||
* uint32_t stripes = 32768; // To produce a 1 MB split key
|
||||
* uint8_t *masterkey;
|
||||
* uint8_t *splitkey = .... read in 1 MB of data...
|
||||
*
|
||||
* masterkey = g_new0(uint8_t, nkey);
|
||||
*
|
||||
* if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALG_SHA256,
|
||||
* nkey, stripes,
|
||||
* splitkey, masterkey, errp) < 0) {
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* ..decrypt data with masterkey...
|
||||
*
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* qcrypto_afsplit_encode:
|
||||
* @hash: the hash algorithm to use for data expansion
|
||||
* @blocklen: the size of @in in bytes
|
||||
* @stripes: the number of times to expand @in in size
|
||||
* @in: the master key to be expanded in size
|
||||
* @out: preallocated buffer to hold the split key
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Split the data in @in, which is @blocklen bytes in
|
||||
* size, to form a larger piece of data @out, which is
|
||||
* @blocklen * @stripes bytes in size.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error;
|
||||
*/
|
||||
int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_afsplit_decode:
|
||||
* @hash: the hash algorithm to use for data compression
|
||||
* @blocklen: the size of @out in bytes
|
||||
* @stripes: the number of times to decrease @in in size
|
||||
* @in: the split key to be recombined
|
||||
* @out: preallocated buffer to hold the master key
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Join the data in @in, which is @blocklen * @stripes
|
||||
* bytes in size, to form the original small piece of
|
||||
* data @out, which is @blocklen bytes in size.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error;
|
||||
*/
|
||||
int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_AFSPLIT_H__ */
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* 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_BLOCK_H__
|
||||
#define QCRYPTO_BLOCK_H__
|
||||
|
||||
#include "crypto/cipher.h"
|
||||
#include "crypto/ivgen.h"
|
||||
|
||||
typedef struct QCryptoBlock QCryptoBlock;
|
||||
|
||||
/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions
|
||||
* and QCryptoBlockOpenOptions in qapi/crypto.json */
|
||||
|
||||
typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block,
|
||||
size_t headerlen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
const uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* qcrypto_block_has_format:
|
||||
* @format: the encryption format
|
||||
* @buf: the data from head of the volume
|
||||
* @len: the length of @buf in bytes
|
||||
*
|
||||
* Given @len bytes of data from the head of a storage volume
|
||||
* in @buf, probe to determine if the volume has the encryption
|
||||
* format specified in @format.
|
||||
*
|
||||
* Returns: true if the data in @buf matches @format
|
||||
*/
|
||||
bool qcrypto_block_has_format(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
size_t buflen);
|
||||
|
||||
typedef enum {
|
||||
QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0),
|
||||
} QCryptoBlockOpenFlags;
|
||||
|
||||
/**
|
||||
* qcrypto_block_open:
|
||||
* @options: the encryption options
|
||||
* @readfunc: callback for reading data from the volume
|
||||
* @opaque: data to pass to @readfunc
|
||||
* @flags: bitmask of QCryptoBlockOpenFlags values
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Create a new block encryption object for an existing
|
||||
* storage volume encrypted with format identified by
|
||||
* the parameters in @options.
|
||||
*
|
||||
* This will use @readfunc to initialize the encryption
|
||||
* context based on the volume header(s), extracting the
|
||||
* master key(s) as required.
|
||||
*
|
||||
* If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then
|
||||
* the open process will be optimized to skip any parts
|
||||
* that are only required to perform I/O. In particular
|
||||
* this would usually avoid the need to decrypt any
|
||||
* master keys. The only thing that can be done with
|
||||
* the resulting QCryptoBlock object would be to query
|
||||
* metadata such as the payload offset. There will be
|
||||
* no cipher or ivgen objects available.
|
||||
*
|
||||
* If any part of initializing the encryption context
|
||||
* fails an error will be returned. This could be due
|
||||
* to the volume being in the wrong format, a cipher
|
||||
* or IV generator algorithm that is not supported,
|
||||
* or incorrect passphrases.
|
||||
*
|
||||
* Returns: a block encryption format, or NULL on error
|
||||
*/
|
||||
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_block_create:
|
||||
* @format: the encryption format
|
||||
* @initfunc: callback for initializing volume header
|
||||
* @writefunc: callback for writing data to the volume header
|
||||
* @opaque: data to pass to @initfunc and @writefunc
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Create a new block encryption object for initializing
|
||||
* a storage volume to be encrypted with format identified
|
||||
* by the parameters in @options.
|
||||
*
|
||||
* This method will allocate space for a new volume header
|
||||
* using @initfunc and then write header data using @writefunc,
|
||||
* generating new master keys, etc as required. Any existing
|
||||
* data present on the volume will be irrevocably destroyed.
|
||||
*
|
||||
* If any part of initializing the encryption context
|
||||
* fails an error will be returned. This could be due
|
||||
* to the volume being in the wrong format, a cipher
|
||||
* or IV generator algorithm that is not supported,
|
||||
* or incorrect passphrases.
|
||||
*
|
||||
* Returns: a block encryption format, or NULL on error
|
||||
*/
|
||||
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* @qcrypto_block_decrypt:
|
||||
* @block: the block encryption object
|
||||
* @startsector: the sector from which @buf was read
|
||||
* @buf: the buffer to decrypt
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Decrypt @len bytes of cipher text in @buf, writing
|
||||
* plain text back into @buf
|
||||
*
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* @qcrypto_block_encrypt:
|
||||
* @block: the block encryption object
|
||||
* @startsector: the sector to which @buf will be written
|
||||
* @buf: the buffer to decrypt
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Encrypt @len bytes of plain text in @buf, writing
|
||||
* cipher text back into @buf
|
||||
*
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_cipher:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the cipher to use for payload encryption
|
||||
*
|
||||
* Returns: the cipher object
|
||||
*/
|
||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_ivgen:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the initialization vector generator to use for
|
||||
* payload encryption
|
||||
*
|
||||
* Returns: the IV generator object
|
||||
*/
|
||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_kdf_hash:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the hash algorithm used with the key derivation
|
||||
* function
|
||||
*
|
||||
* Returns: the hash algorithm
|
||||
*/
|
||||
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_payload_offset:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the offset to the payload indicated by the
|
||||
* encryption header, in bytes.
|
||||
*
|
||||
* Returns: the payload offset in bytes
|
||||
*/
|
||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_free:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Release all resources associated with the encryption
|
||||
* object
|
||||
*/
|
||||
void qcrypto_block_free(QCryptoBlock *block);
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_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,152 @@
|
|||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* 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_PBKDF_H__
|
||||
#define QCRYPTO_PBKDF_H__
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/**
|
||||
* This module provides an interface to the PBKDF2 algorithm
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/PBKDF2
|
||||
*
|
||||
* <example>
|
||||
* <title>Generating an AES encryption key from a user password</title>
|
||||
* <programlisting>
|
||||
* #include "crypto/cipher.h"
|
||||
* #include "crypto/random.h"
|
||||
* #include "crypto/pbkdf.h"
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* char *password = "a-typical-awful-user-password";
|
||||
* size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALG_AES_128);
|
||||
* uint8_t *salt = g_new0(uint8_t, nkey);
|
||||
* uint8_t *key = g_new0(uint8_t, nkey);
|
||||
* int iterations;
|
||||
* QCryptoCipher *cipher;
|
||||
*
|
||||
* if (qcrypto_random_bytes(salt, nkey, errp) < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
|
||||
* (const uint8_t *)password,
|
||||
* strlen(password),
|
||||
* salt, nkey, errp);
|
||||
* if (iterations < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* if (qcrypto_pbkdf2(QCRYPTO_HASH_ALG_SHA256,
|
||||
* (const uint8_t *)password, strlen(password),
|
||||
* salt, nkey, iterations, key, nkey, errp) < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* g_free(salt);
|
||||
*
|
||||
* cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
* QCRYPTO_CIPHER_MODE_ECB,
|
||||
* key, nkey, errp);
|
||||
* g_free(key);
|
||||
*
|
||||
* ....encrypt some data...
|
||||
*
|
||||
* qcrypto_cipher_free(cipher);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2_supports:
|
||||
* @hash: the hash algorithm
|
||||
*
|
||||
* Determine if the current build supports the PBKDF2 algorithm
|
||||
* in combination with the hash @hash.
|
||||
*
|
||||
* Returns true if supported, false otherwise
|
||||
*/
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2:
|
||||
* @hash: the hash algorithm to use
|
||||
* @key: the user password / key
|
||||
* @nkey: the length of @key in bytes
|
||||
* @salt: a random salt
|
||||
* @nsalt: length of @salt in bytes
|
||||
* @iterations: the number of iterations to compute
|
||||
* @out: pointer to pre-allocated buffer to hold output
|
||||
* @nout: length of @out in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Apply the PBKDF2 algorithm to derive an encryption
|
||||
* key from a user password provided in @key. The
|
||||
* @salt parameter is used to perturb the algorithm.
|
||||
* The @iterations count determines how many times
|
||||
* the hashing process is run, which influences how
|
||||
* hard it is to crack the key. The number of @iterations
|
||||
* should be large enough such that the algorithm takes
|
||||
* 1 second or longer to derive a key. The derived key
|
||||
* will be stored in the preallocated buffer @out.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2_count_iters:
|
||||
* @hash: the hash algorithm to use
|
||||
* @key: the user password / key
|
||||
* @nkey: the length of @key in bytes
|
||||
* @salt: a random salt
|
||||
* @nsalt: length of @salt in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Time the PBKDF2 algorithm to determine how many
|
||||
* iterations are required to derive an encryption
|
||||
* key from a user password provided in @key in 1
|
||||
* second of compute time. The result of this can
|
||||
* be used as a the @iterations parameter of a later
|
||||
* call to qcrypto_pbkdf2().
|
||||
*
|
||||
* Returns: number of iterations in 1 second, -1 on error
|
||||
*/
|
||||
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_PBKDF_H__ */
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* 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_RANDOM_H__
|
||||
#define QCRYPTO_RANDOM_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_random_bytes:
|
||||
* @buf: the buffer to fill
|
||||
* @buflen: length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Fill @buf with @buflen bytes of cryptographically strong
|
||||
* random data
|
||||
*
|
||||
* Returns 0 on sucess, -1 on error
|
||||
*/
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
||||
#endif /* QCRYPTO_RANDOM_H__ */
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QCRYPTO_XTS_H_
|
||||
#define QCRYPTO_XTS_H_
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
||||
#define XTS_BLOCK_SIZE 16
|
||||
|
||||
typedef void xts_cipher_func(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data decryption
|
||||
* @tweakctx: the cipher context for tweak decryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the decrypted plaintext
|
||||
* @src: buffer providing the ciphertext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data encryption
|
||||
* @tweakctx: the cipher context for tweak encryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the encrypted ciphertext
|
||||
* @src: buffer providing the plaintext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
|
||||
#endif /* QCRYPTO_XTS_H_ */
|
146
qapi/crypto.json
146
qapi/crypto.json
|
@ -59,11 +59,22 @@
|
|||
# @aes-192: AES with 192 bit / 24 byte keys
|
||||
# @aes-256: AES with 256 bit / 32 byte keys
|
||||
# @des-rfb: RFB specific variant of single DES. Do not use except in VNC.
|
||||
# @cast5-128: Cast5 with 128 bit / 16 byte keys
|
||||
# @serpent-128: Serpent with 128 bit / 16 byte keys
|
||||
# @serpent-192: Serpent with 192 bit / 24 byte keys
|
||||
# @serpent-256: Serpent with 256 bit / 32 byte keys
|
||||
# @twofish-128: Twofish with 128 bit / 16 byte keys
|
||||
# @twofish-192: Twofish with 192 bit / 24 byte keys
|
||||
# @twofish-256: Twofish with 256 bit / 32 byte keys
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'enum': 'QCryptoCipherAlgorithm',
|
||||
'prefix': 'QCRYPTO_CIPHER_ALG',
|
||||
'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb']}
|
||||
'data': ['aes-128', 'aes-192', 'aes-256',
|
||||
'des-rfb',
|
||||
'cast5-128',
|
||||
'serpent-128', 'serpent-192', 'serpent-256',
|
||||
'twofish-128', 'twofish-192', 'twofish-256']}
|
||||
|
||||
|
||||
##
|
||||
|
@ -73,8 +84,139 @@
|
|||
#
|
||||
# @ecb: Electronic Code Book
|
||||
# @cbc: Cipher Block Chaining
|
||||
# @xts: XEX with tweaked code book and ciphertext stealing
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'enum': 'QCryptoCipherMode',
|
||||
'prefix': 'QCRYPTO_CIPHER_MODE',
|
||||
'data': ['ecb', 'cbc']}
|
||||
'data': ['ecb', 'cbc', 'xts']}
|
||||
|
||||
|
||||
##
|
||||
# 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']}
|
||||
|
||||
##
|
||||
# QCryptoBlockFormat:
|
||||
#
|
||||
# The supported full disk encryption formats
|
||||
#
|
||||
# @qcow: QCow/QCow2 built-in AES-CBC encryption. Use only
|
||||
# for liberating data from old images.
|
||||
# @luks: LUKS encryption format. Recommended for new images
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'enum': 'QCryptoBlockFormat',
|
||||
# 'prefix': 'QCRYPTO_BLOCK_FORMAT',
|
||||
'data': ['qcow', 'luks']}
|
||||
|
||||
##
|
||||
# QCryptoBlockOptionsBase:
|
||||
#
|
||||
# The common options that apply to all full disk
|
||||
# encryption formats
|
||||
#
|
||||
# @format: the encryption format
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'QCryptoBlockOptionsBase',
|
||||
'data': { 'format': 'QCryptoBlockFormat' }}
|
||||
|
||||
##
|
||||
# QCryptoBlockOptionsQCow:
|
||||
#
|
||||
# The options that apply to QCow/QCow2 AES-CBC encryption format
|
||||
#
|
||||
# @key-secret: #optional the ID of a QCryptoSecret object providing the
|
||||
# decryption key. Mandatory except when probing image for
|
||||
# metadata only.
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'QCryptoBlockOptionsQCow',
|
||||
'data': { '*key-secret': 'str' }}
|
||||
|
||||
##
|
||||
# QCryptoBlockOptionsLUKS:
|
||||
#
|
||||
# The options that apply to LUKS encryption format
|
||||
#
|
||||
# @key-secret: #optional the ID of a QCryptoSecret object providing the
|
||||
# decryption key. Mandatory except when probing image for
|
||||
# metadata only.
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'QCryptoBlockOptionsLUKS',
|
||||
'data': { '*key-secret': 'str' }}
|
||||
|
||||
|
||||
##
|
||||
# QCryptoBlockCreateOptionsLUKS:
|
||||
#
|
||||
# The options that apply to LUKS encryption format initialization
|
||||
#
|
||||
# @cipher-alg: #optional the cipher algorithm for data encryption
|
||||
# Currently defaults to 'aes'.
|
||||
# @cipher-mode: #optional the cipher mode for data encryption
|
||||
# Currently defaults to 'cbc'
|
||||
# @ivgen-alg: #optional the initialization vector generator
|
||||
# Currently defaults to 'essiv'
|
||||
# @ivgen-hash-alg: #optional the initialization vector generator hash
|
||||
# Currently defaults to 'sha256'
|
||||
# @hash-alg: #optional the master key hash algorithm
|
||||
# Currently defaults to 'sha256'
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
|
||||
'base': 'QCryptoBlockOptionsLUKS',
|
||||
'data': { '*cipher-alg': 'QCryptoCipherAlgorithm',
|
||||
'*cipher-mode': 'QCryptoCipherMode',
|
||||
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
|
||||
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
|
||||
'*hash-alg': 'QCryptoHashAlgorithm'}}
|
||||
|
||||
|
||||
##
|
||||
# QCryptoBlockOpenOptions:
|
||||
#
|
||||
# The options that are available for all encryption formats
|
||||
# when opening an existing volume
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'union': 'QCryptoBlockOpenOptions',
|
||||
'base': 'QCryptoBlockOptionsBase',
|
||||
'discriminator': 'format',
|
||||
'data': { 'qcow': 'QCryptoBlockOptionsQCow',
|
||||
'luks': 'QCryptoBlockOptionsLUKS' } }
|
||||
|
||||
|
||||
##
|
||||
# QCryptoBlockCreateOptions:
|
||||
#
|
||||
# The options that are available for all encryption formats
|
||||
# when initializing a new volume
|
||||
#
|
||||
# Since: 2.6
|
||||
##
|
||||
{ 'union': 'QCryptoBlockCreateOptions',
|
||||
'base': 'QCryptoBlockOptionsBase',
|
||||
'discriminator': 'format',
|
||||
'data': { 'qcow': 'QCryptoBlockOptionsQCow',
|
||||
'luks': 'QCryptoBlockCreateOptionsLUKS' } }
|
||||
|
|
|
@ -12,8 +12,12 @@ test-base64
|
|||
test-bitops
|
||||
test-blockjob-txn
|
||||
test-coroutine
|
||||
test-crypto-afsplit
|
||||
test-crypto-block
|
||||
test-crypto-cipher
|
||||
test-crypto-hash
|
||||
test-crypto-ivgen
|
||||
test-crypto-pbkdf
|
||||
test-crypto-secret
|
||||
test-crypto-tlscredsx509
|
||||
test-crypto-tlscredsx509-work/
|
||||
|
@ -22,6 +26,7 @@ test-crypto-tlssession
|
|||
test-crypto-tlssession-work/
|
||||
test-crypto-tlssession-client/
|
||||
test-crypto-tlssession-server/
|
||||
test-crypto-xts
|
||||
test-cutils
|
||||
test-hbitmap
|
||||
test-int128
|
||||
|
|
|
@ -92,6 +92,11 @@ check-unit-$(CONFIG_GNUTLS) += tests/test-io-channel-tls$(EXESUF)
|
|||
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-unit-y += tests/test-crypto-afsplit$(EXESUF)
|
||||
check-unit-y += tests/test-crypto-xts$(EXESUF)
|
||||
check-unit-y += tests/test-crypto-block$(EXESUF)
|
||||
|
||||
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
|
||||
|
||||
|
@ -472,6 +477,7 @@ tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y)
|
|||
tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y)
|
||||
|
||||
tests/crypto-tls-x509-helpers.o-cflags := $(TASN1_CFLAGS)
|
||||
tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS)
|
||||
|
@ -496,6 +502,10 @@ tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \
|
|||
tests/io-channel-helpers.o $(test-io-obj-y)
|
||||
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)
|
||||
tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-block$(EXESUF): tests/test-crypto-block.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
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* QEMU Crypto anti-forensic splitter
|
||||
*
|
||||
* 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/init.h"
|
||||
#include "crypto/afsplit.h"
|
||||
|
||||
typedef struct QCryptoAFSplitTestData QCryptoAFSplitTestData;
|
||||
struct QCryptoAFSplitTestData {
|
||||
const char *path;
|
||||
QCryptoHashAlgorithm hash;
|
||||
uint32_t stripes;
|
||||
size_t blocklen;
|
||||
const uint8_t *key;
|
||||
const uint8_t *splitkey;
|
||||
};
|
||||
|
||||
static QCryptoAFSplitTestData test_data[] = {
|
||||
{
|
||||
.path = "/crypto/afsplit/sha256/5",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA256,
|
||||
.stripes = 5,
|
||||
.blocklen = 32,
|
||||
.key = (const uint8_t *)
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
|
||||
"\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
|
||||
.splitkey = (const uint8_t *)
|
||||
"\xfd\xd2\x73\xb1\x7d\x99\x93\x34"
|
||||
"\x70\xde\xfa\x07\xc5\xac\x58\xd2"
|
||||
"\x30\x67\x2f\x1a\x35\x43\x60\x7d"
|
||||
"\x77\x02\xdb\x62\x3c\xcb\x2c\x33"
|
||||
"\x48\x08\xb6\xf1\x7c\xa3\x20\xa0"
|
||||
"\xad\x2d\x4c\xf3\xcd\x18\x6f\x53"
|
||||
"\xf9\xe8\xe7\x59\x27\x3c\xa9\x54"
|
||||
"\x61\x87\xb3\xaf\xf6\xf7\x7e\x64"
|
||||
"\x86\xaa\x89\x7f\x1f\x9f\xdb\x86"
|
||||
"\xf4\xa2\x16\xff\xa3\x4f\x8c\xa1"
|
||||
"\x59\xc4\x23\x34\x28\xc4\x77\x71"
|
||||
"\x83\xd4\xcd\x8e\x89\x1b\xc7\xc5"
|
||||
"\xae\x4d\xa9\xcd\xc9\x72\x85\x70"
|
||||
"\x13\x68\x52\x83\xfc\xb8\x11\x72"
|
||||
"\xba\x3d\xc6\x4a\x28\xfa\xe2\x86"
|
||||
"\x7b\x27\xab\x58\xe1\xa4\xca\xf6"
|
||||
"\x9e\xbc\xfe\x0c\x92\x79\xb3\xec"
|
||||
"\x1c\x5f\x79\x3b\x0d\x1e\xaa\x1a"
|
||||
"\x77\x0f\x70\x19\x4b\xc8\x80\xee"
|
||||
"\x27\x7c\x6e\x4a\x91\x96\x5c\xf4"
|
||||
},
|
||||
{
|
||||
.path = "/crypto/afsplit/sha256/5000",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA256,
|
||||
.stripes = 5000,
|
||||
.blocklen = 16,
|
||||
.key = (const uint8_t *)
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
},
|
||||
{
|
||||
.path = "/crypto/afsplit/sha1/1000",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.stripes = 1000,
|
||||
.blocklen = 32,
|
||||
.key = (const uint8_t *)
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
|
||||
"\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
|
||||
},
|
||||
{
|
||||
.path = "/crypto/afsplit/sha256/big",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA256,
|
||||
.stripes = 1000,
|
||||
.blocklen = 64,
|
||||
.key = (const uint8_t *)
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static inline char hex(int i)
|
||||
{
|
||||
if (i < 10) {
|
||||
return '0' + i;
|
||||
}
|
||||
return 'a' + (i - 10);
|
||||
}
|
||||
|
||||
static char *hex_string(const uint8_t *bytes,
|
||||
size_t len)
|
||||
{
|
||||
char *hexstr = g_new0(char, len * 2 + 1);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
hexstr[i * 2] = hex((bytes[i] >> 4) & 0xf);
|
||||
hexstr[i * 2 + 1] = hex(bytes[i] & 0xf);
|
||||
}
|
||||
hexstr[len * 2] = '\0';
|
||||
|
||||
return hexstr;
|
||||
}
|
||||
|
||||
static void test_afsplit(const void *opaque)
|
||||
{
|
||||
const QCryptoAFSplitTestData *data = opaque;
|
||||
size_t splitlen = data->blocklen * data->stripes;
|
||||
uint8_t *splitkey = g_new0(uint8_t, splitlen);
|
||||
uint8_t *key = g_new0(uint8_t, data->blocklen);
|
||||
gchar *expect, *actual;
|
||||
|
||||
/* First time we round-trip the key */
|
||||
qcrypto_afsplit_encode(data->hash,
|
||||
data->blocklen, data->stripes,
|
||||
data->key, splitkey,
|
||||
&error_abort);
|
||||
|
||||
qcrypto_afsplit_decode(data->hash,
|
||||
data->blocklen, data->stripes,
|
||||
splitkey, key,
|
||||
&error_abort);
|
||||
|
||||
expect = hex_string(data->key, data->blocklen);
|
||||
actual = hex_string(key, data->blocklen);
|
||||
|
||||
g_assert_cmpstr(actual, ==, expect);
|
||||
|
||||
g_free(actual);
|
||||
g_free(expect);
|
||||
|
||||
/* Second time we merely try decoding a previous split */
|
||||
if (data->splitkey) {
|
||||
memset(key, 0, data->blocklen);
|
||||
|
||||
qcrypto_afsplit_decode(data->hash,
|
||||
data->blocklen, data->stripes,
|
||||
data->splitkey, key,
|
||||
&error_abort);
|
||||
|
||||
expect = hex_string(data->key, data->blocklen);
|
||||
actual = hex_string(key, data->blocklen);
|
||||
|
||||
g_assert_cmpstr(actual, ==, expect);
|
||||
|
||||
g_free(actual);
|
||||
g_free(expect);
|
||||
}
|
||||
|
||||
g_free(key);
|
||||
g_free(splitkey);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
if (!qcrypto_hash_supports(test_data[i].hash)) {
|
||||
continue;
|
||||
}
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_afsplit);
|
||||
}
|
||||
return g_test_run();
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* QEMU Crypto block encryption
|
||||
*
|
||||
* Copyright (c) 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/init.h"
|
||||
#include "crypto/block.h"
|
||||
#include "qemu/buffer.h"
|
||||
#include "crypto/secret.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_UUID) && (defined(_WIN32) || defined RUSAGE_THREAD)
|
||||
#define TEST_LUKS
|
||||
#else
|
||||
#undef TEST_LUKS
|
||||
#endif
|
||||
|
||||
static QCryptoBlockCreateOptions qcow_create_opts = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
|
||||
.u.qcow = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
},
|
||||
};
|
||||
|
||||
static QCryptoBlockOpenOptions qcow_open_opts = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
|
||||
.u.qcow = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#ifdef TEST_LUKS
|
||||
static QCryptoBlockOpenOptions luks_open_opts = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
.u.luks = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* Creation with all default values */
|
||||
static QCryptoBlockCreateOptions luks_create_opts_default = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
.u.luks = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* ...and with explicit values */
|
||||
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
.u.luks = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
.has_cipher_alg = true,
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
|
||||
.has_cipher_mode = true,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
|
||||
.has_ivgen_alg = true,
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = {
|
||||
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
|
||||
.u.luks = {
|
||||
.has_key_secret = true,
|
||||
.key_secret = (char *)"sec0",
|
||||
.has_cipher_alg = true,
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
|
||||
.has_cipher_mode = true,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
|
||||
.has_ivgen_alg = true,
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
|
||||
.has_ivgen_hash_alg = true,
|
||||
.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256,
|
||||
.has_hash_alg = true,
|
||||
.hash_alg = QCRYPTO_HASH_ALG_SHA1,
|
||||
},
|
||||
};
|
||||
#endif /* TEST_LUKS */
|
||||
|
||||
|
||||
static struct QCryptoBlockTestData {
|
||||
const char *path;
|
||||
QCryptoBlockCreateOptions *create_opts;
|
||||
QCryptoBlockOpenOptions *open_opts;
|
||||
|
||||
bool expect_header;
|
||||
|
||||
QCryptoCipherAlgorithm cipher_alg;
|
||||
QCryptoCipherMode cipher_mode;
|
||||
QCryptoHashAlgorithm hash_alg;
|
||||
|
||||
QCryptoIVGenAlgorithm ivgen_alg;
|
||||
QCryptoHashAlgorithm ivgen_hash;
|
||||
|
||||
bool slow;
|
||||
} test_data[] = {
|
||||
{
|
||||
.path = "/crypto/block/qcow",
|
||||
.create_opts = &qcow_create_opts,
|
||||
.open_opts = &qcow_open_opts,
|
||||
|
||||
.expect_header = false,
|
||||
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
|
||||
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
},
|
||||
#ifdef TEST_LUKS
|
||||
{
|
||||
.path = "/crypto/block/luks/default",
|
||||
.create_opts = &luks_create_opts_default,
|
||||
.open_opts = &luks_open_opts,
|
||||
|
||||
.expect_header = true,
|
||||
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.hash_alg = QCRYPTO_HASH_ALG_SHA256,
|
||||
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
|
||||
.slow = true,
|
||||
},
|
||||
{
|
||||
.path = "/crypto/block/luks/aes-256-cbc-plain64",
|
||||
.create_opts = &luks_create_opts_aes256_cbc_plain64,
|
||||
.open_opts = &luks_open_opts,
|
||||
|
||||
.expect_header = true,
|
||||
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
|
||||
.hash_alg = QCRYPTO_HASH_ALG_SHA256,
|
||||
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
|
||||
.slow = true,
|
||||
},
|
||||
{
|
||||
.path = "/crypto/block/luks/aes-256-cbc-essiv",
|
||||
.create_opts = &luks_create_opts_aes256_cbc_essiv,
|
||||
.open_opts = &luks_open_opts,
|
||||
|
||||
.expect_header = true,
|
||||
|
||||
.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
|
||||
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
|
||||
.hash_alg = QCRYPTO_HASH_ALG_SHA1,
|
||||
|
||||
.ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
|
||||
.ivgen_hash = QCRYPTO_HASH_ALG_SHA256,
|
||||
|
||||
.slow = true,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static ssize_t test_block_read_func(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
Buffer *header = opaque;
|
||||
|
||||
g_assert_cmpint(offset + buflen, <=, header->capacity);
|
||||
|
||||
memcpy(buf, header->buffer + offset, buflen);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t test_block_init_func(QCryptoBlock *block,
|
||||
size_t headerlen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
Buffer *header = opaque;
|
||||
|
||||
g_assert_cmpint(header->capacity, ==, 0);
|
||||
|
||||
buffer_reserve(header, headerlen);
|
||||
|
||||
return headerlen;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t test_block_write_func(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
const uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque)
|
||||
{
|
||||
Buffer *header = opaque;
|
||||
|
||||
g_assert_cmpint(buflen + offset, <=, header->capacity);
|
||||
|
||||
memcpy(header->buffer + offset, buf, buflen);
|
||||
header->offset = offset + buflen;
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
static Object *test_block_secret(void)
|
||||
{
|
||||
return object_new_with_props(
|
||||
TYPE_QCRYPTO_SECRET,
|
||||
object_get_objects_root(),
|
||||
"sec0",
|
||||
&error_abort,
|
||||
"data", "123456",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void test_block_assert_setup(const struct QCryptoBlockTestData *data,
|
||||
QCryptoBlock *blk)
|
||||
{
|
||||
QCryptoIVGen *ivgen;
|
||||
QCryptoCipher *cipher;
|
||||
|
||||
ivgen = qcrypto_block_get_ivgen(blk);
|
||||
cipher = qcrypto_block_get_cipher(blk);
|
||||
|
||||
g_assert(ivgen);
|
||||
g_assert(cipher);
|
||||
|
||||
g_assert_cmpint(data->cipher_alg, ==, cipher->alg);
|
||||
g_assert_cmpint(data->cipher_mode, ==, cipher->mode);
|
||||
g_assert_cmpint(data->hash_alg, ==,
|
||||
qcrypto_block_get_kdf_hash(blk));
|
||||
|
||||
g_assert_cmpint(data->ivgen_alg, ==,
|
||||
qcrypto_ivgen_get_algorithm(ivgen));
|
||||
g_assert_cmpint(data->ivgen_hash, ==,
|
||||
qcrypto_ivgen_get_hash(ivgen));
|
||||
}
|
||||
|
||||
|
||||
static void test_block(gconstpointer opaque)
|
||||
{
|
||||
const struct QCryptoBlockTestData *data = opaque;
|
||||
QCryptoBlock *blk;
|
||||
Buffer header;
|
||||
Object *sec = test_block_secret();
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
buffer_init(&header, "header");
|
||||
|
||||
blk = qcrypto_block_create(data->create_opts,
|
||||
test_block_init_func,
|
||||
test_block_write_func,
|
||||
&header,
|
||||
&error_abort);
|
||||
g_assert(blk);
|
||||
|
||||
if (data->expect_header) {
|
||||
g_assert_cmpint(header.capacity, >, 0);
|
||||
} else {
|
||||
g_assert_cmpint(header.capacity, ==, 0);
|
||||
}
|
||||
|
||||
test_block_assert_setup(data, blk);
|
||||
|
||||
qcrypto_block_free(blk);
|
||||
object_unparent(sec);
|
||||
|
||||
/* Ensure we can't open without the secret */
|
||||
blk = qcrypto_block_open(data->open_opts,
|
||||
test_block_read_func,
|
||||
&header,
|
||||
0,
|
||||
NULL);
|
||||
g_assert(blk == NULL);
|
||||
|
||||
/* Ensure we can't open without the secret, unless NO_IO */
|
||||
blk = qcrypto_block_open(data->open_opts,
|
||||
test_block_read_func,
|
||||
&header,
|
||||
QCRYPTO_BLOCK_OPEN_NO_IO,
|
||||
&error_abort);
|
||||
|
||||
g_assert(qcrypto_block_get_cipher(blk) == NULL);
|
||||
g_assert(qcrypto_block_get_ivgen(blk) == NULL);
|
||||
|
||||
qcrypto_block_free(blk);
|
||||
|
||||
|
||||
/* Now open for real with secret */
|
||||
sec = test_block_secret();
|
||||
blk = qcrypto_block_open(data->open_opts,
|
||||
test_block_read_func,
|
||||
&header,
|
||||
0,
|
||||
&error_abort);
|
||||
g_assert(blk);
|
||||
|
||||
test_block_assert_setup(data, blk);
|
||||
|
||||
qcrypto_block_free(blk);
|
||||
|
||||
object_unparent(sec);
|
||||
|
||||
buffer_free(&header);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
if (test_data[i].open_opts->format == Q_CRYPTO_BLOCK_FORMAT_LUKS &&
|
||||
!qcrypto_hash_supports(test_data[i].hash_alg)) {
|
||||
continue;
|
||||
}
|
||||
if (!test_data[i].slow ||
|
||||
g_test_slow()) {
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_block);
|
||||
}
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
|
@ -165,6 +165,211 @@ static QCryptoCipherTestData test_data[] = {
|
|||
"ffd29f1bb5596ad94ea2d8e6196b7f09"
|
||||
"30d8ed0bf2773af36dd82a6280c20926",
|
||||
},
|
||||
{
|
||||
/* RFC 2144, Appendix B.1 */
|
||||
.path = "/crypto/cipher/cast5-128",
|
||||
.alg = QCRYPTO_CIPHER_ALG_CAST5_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "0123456712345678234567893456789A",
|
||||
.plaintext = "0123456789abcdef",
|
||||
.ciphertext = "238b4fe5847e44b2",
|
||||
},
|
||||
{
|
||||
/* libgcrypt serpent.c */
|
||||
.path = "/crypto/cipher/serpent-128",
|
||||
.alg = QCRYPTO_CIPHER_ALG_SERPENT_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "00000000000000000000000000000000",
|
||||
.plaintext = "d29d576fcea3a3a7ed9099f29273d78e",
|
||||
.ciphertext = "b2288b968ae8b08648d1ce9606fd992d",
|
||||
},
|
||||
{
|
||||
/* libgcrypt serpent.c */
|
||||
.path = "/crypto/cipher/serpent-192",
|
||||
.alg = QCRYPTO_CIPHER_ALG_SERPENT_192,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "00000000000000000000000000000000"
|
||||
"0000000000000000",
|
||||
.plaintext = "d29d576fceaba3a7ed9899f2927bd78e",
|
||||
.ciphertext = "130e353e1037c22405e8faefb2c3c3e9",
|
||||
},
|
||||
{
|
||||
/* libgcrypt serpent.c */
|
||||
.path = "/crypto/cipher/serpent-256a",
|
||||
.alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
.plaintext = "d095576fcea3e3a7ed98d9f29073d78e",
|
||||
.ciphertext = "b90ee5862de69168f2bdd5125b45472b",
|
||||
},
|
||||
{
|
||||
/* libgcrypt serpent.c */
|
||||
.path = "/crypto/cipher/serpent-256b",
|
||||
.alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
.plaintext = "00000000010000000200000003000000",
|
||||
.ciphertext = "2061a42782bd52ec691ec383b03ba77c",
|
||||
},
|
||||
{
|
||||
/* Twofish paper "Known Answer Test" */
|
||||
.path = "/crypto/cipher/twofish-128",
|
||||
.alg = QCRYPTO_CIPHER_ALG_TWOFISH_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "d491db16e7b1c39e86cb086b789f5419",
|
||||
.plaintext = "019f9809de1711858faac3a3ba20fbc3",
|
||||
.ciphertext = "6363977de839486297e661c6c9d668eb",
|
||||
},
|
||||
{
|
||||
/* Twofish paper "Known Answer Test", I=3 */
|
||||
.path = "/crypto/cipher/twofish-192",
|
||||
.alg = QCRYPTO_CIPHER_ALG_TWOFISH_192,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "88b2b2706b105e36b446bb6d731a1e88"
|
||||
"efa71f788965bd44",
|
||||
.plaintext = "39da69d6ba4997d585b6dc073ca341b2",
|
||||
.ciphertext = "182b02d81497ea45f9daacdc29193a65",
|
||||
},
|
||||
{
|
||||
/* Twofish paper "Known Answer Test", I=4 */
|
||||
.path = "/crypto/cipher/twofish-256",
|
||||
.alg = QCRYPTO_CIPHER_ALG_TWOFISH_256,
|
||||
.mode = QCRYPTO_CIPHER_MODE_ECB,
|
||||
.key = "d43bb7556ea32e46f2a282b7d45b4e0d"
|
||||
"57ff739d4dc92c1bd7fc01700cc8216f",
|
||||
.plaintext = "90afe91bb288544f2c32dc239b2635e6",
|
||||
.ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
|
||||
},
|
||||
{
|
||||
/* #1 32 byte key, 32 byte PTX */
|
||||
.path = "/crypto/cipher/aes-xts-128-1",
|
||||
.alg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.key =
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
.iv =
|
||||
"00000000000000000000000000000000",
|
||||
.plaintext =
|
||||
"00000000000000000000000000000000"
|
||||
"00000000000000000000000000000000",
|
||||
.ciphertext =
|
||||
"917cf69ebd68b2ec9b9fe9a3eadda692"
|
||||
"cd43d2f59598ed858c02c2652fbf922e",
|
||||
},
|
||||
{
|
||||
/* #2, 32 byte key, 32 byte PTX */
|
||||
.path = "/crypto/cipher/aes-xts-128-2",
|
||||
.alg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.key =
|
||||
"11111111111111111111111111111111"
|
||||
"22222222222222222222222222222222",
|
||||
.iv =
|
||||
"33333333330000000000000000000000",
|
||||
.plaintext =
|
||||
"44444444444444444444444444444444"
|
||||
"44444444444444444444444444444444",
|
||||
.ciphertext =
|
||||
"c454185e6a16936e39334038acef838b"
|
||||
"fb186fff7480adc4289382ecd6d394f0",
|
||||
},
|
||||
{
|
||||
/* #5 from xts.7, 32 byte key, 32 byte PTX */
|
||||
.path = "/crypto/cipher/aes-xts-128-3",
|
||||
.alg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.key =
|
||||
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0"
|
||||
"bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0",
|
||||
.iv =
|
||||
"9a785634120000000000000000000000",
|
||||
.plaintext =
|
||||
"44444444444444444444444444444444"
|
||||
"44444444444444444444444444444444",
|
||||
.ciphertext =
|
||||
"b01f86f8edc1863706fa8a4253e34f28"
|
||||
"af319de38334870f4dd1f94cbe9832f1",
|
||||
},
|
||||
{
|
||||
/* #4, 32 byte key, 512 byte PTX */
|
||||
.path = "/crypto/cipher/aes-xts-128-4",
|
||||
.alg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.key =
|
||||
"27182818284590452353602874713526"
|
||||
"31415926535897932384626433832795",
|
||||
.iv =
|
||||
"00000000000000000000000000000000",
|
||||
.plaintext =
|
||||
"000102030405060708090a0b0c0d0e0f"
|
||||
"101112131415161718191a1b1c1d1e1f"
|
||||
"202122232425262728292a2b2c2d2e2f"
|
||||
"303132333435363738393a3b3c3d3e3f"
|
||||
"404142434445464748494a4b4c4d4e4f"
|
||||
"505152535455565758595a5b5c5d5e5f"
|
||||
"606162636465666768696a6b6c6d6e6f"
|
||||
"707172737475767778797a7b7c7d7e7f"
|
||||
"808182838485868788898a8b8c8d8e8f"
|
||||
"909192939495969798999a9b9c9d9e9f"
|
||||
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
|
||||
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
|
||||
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
|
||||
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
|
||||
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||
"000102030405060708090a0b0c0d0e0f"
|
||||
"101112131415161718191a1b1c1d1e1f"
|
||||
"202122232425262728292a2b2c2d2e2f"
|
||||
"303132333435363738393a3b3c3d3e3f"
|
||||
"404142434445464748494a4b4c4d4e4f"
|
||||
"505152535455565758595a5b5c5d5e5f"
|
||||
"606162636465666768696a6b6c6d6e6f"
|
||||
"707172737475767778797a7b7c7d7e7f"
|
||||
"808182838485868788898a8b8c8d8e8f"
|
||||
"909192939495969798999a9b9c9d9e9f"
|
||||
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
|
||||
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
|
||||
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
|
||||
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
|
||||
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
||||
.ciphertext =
|
||||
"27a7479befa1d476489f308cd4cfa6e2"
|
||||
"a96e4bbe3208ff25287dd3819616e89c"
|
||||
"c78cf7f5e543445f8333d8fa7f560000"
|
||||
"05279fa5d8b5e4ad40e736ddb4d35412"
|
||||
"328063fd2aab53e5ea1e0a9f332500a5"
|
||||
"df9487d07a5c92cc512c8866c7e860ce"
|
||||
"93fdf166a24912b422976146ae20ce84"
|
||||
"6bb7dc9ba94a767aaef20c0d61ad0265"
|
||||
"5ea92dc4c4e41a8952c651d33174be51"
|
||||
"a10c421110e6d81588ede82103a252d8"
|
||||
"a750e8768defffed9122810aaeb99f91"
|
||||
"72af82b604dc4b8e51bcb08235a6f434"
|
||||
"1332e4ca60482a4ba1a03b3e65008fc5"
|
||||
"da76b70bf1690db4eae29c5f1badd03c"
|
||||
"5ccf2a55d705ddcd86d449511ceb7ec3"
|
||||
"0bf12b1fa35b913f9f747a8afd1b130e"
|
||||
"94bff94effd01a91735ca1726acd0b19"
|
||||
"7c4e5b03393697e126826fb6bbde8ecc"
|
||||
"1e08298516e2c9ed03ff3c1b7860f6de"
|
||||
"76d4cecd94c8119855ef5297ca67e9f3"
|
||||
"e7ff72b1e99785ca0a7e7720c5b36dc6"
|
||||
"d72cac9574c8cbbc2f801e23e56fd344"
|
||||
"b07f22154beba0f08ce8891e643ed995"
|
||||
"c94d9a69c9f1b5f499027a78572aeebd"
|
||||
"74d20cc39881c213ee770b1010e4bea7"
|
||||
"18846977ae119f7a023ab58cca0ad752"
|
||||
"afe656bb3c17256a9f6e9bf19fdd5a38"
|
||||
"fc82bbe872c5539edb609ef4f79c203e"
|
||||
"bb140f2e583cb2ad15b4aa5b655016a8"
|
||||
"449277dbd477ef2c8d6c017db738b18d"
|
||||
"eb4a427d1923ce3ff262735779a418f2"
|
||||
"0a282df920147beabe421ee5319d0568",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -251,7 +456,11 @@ static void test_cipher(const void *opaque)
|
|||
blocksize = qcrypto_cipher_get_block_len(data->alg);
|
||||
ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode);
|
||||
|
||||
g_assert_cmpint(keysize, ==, nkey);
|
||||
if (data->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
g_assert_cmpint(keysize * 2, ==, nkey);
|
||||
} else {
|
||||
g_assert_cmpint(keysize, ==, nkey);
|
||||
}
|
||||
g_assert_cmpint(ivsize, ==, niv);
|
||||
if (niv) {
|
||||
g_assert_cmpint(blocksize, ==, niv);
|
||||
|
@ -380,7 +589,9 @@ int main(int argc, char **argv)
|
|||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher);
|
||||
if (qcrypto_cipher_supports(test_data[i].alg)) {
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher);
|
||||
}
|
||||
}
|
||||
|
||||
g_test_add_func("/crypto/cipher/null-iv",
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* QEMU Crypto cipher 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/init.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if ((defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)) && \
|
||||
(defined(_WIN32) || defined(RUSAGE_THREAD)))
|
||||
#include "crypto/pbkdf.h"
|
||||
|
||||
typedef struct QCryptoPbkdfTestData QCryptoPbkdfTestData;
|
||||
struct QCryptoPbkdfTestData {
|
||||
const char *path;
|
||||
QCryptoHashAlgorithm hash;
|
||||
unsigned int iterations;
|
||||
const char *key;
|
||||
size_t nkey;
|
||||
const char *salt;
|
||||
size_t nsalt;
|
||||
const char *out;
|
||||
size_t nout;
|
||||
bool slow;
|
||||
};
|
||||
|
||||
/* This test data comes from cryptsetup package
|
||||
*
|
||||
* $SRC/lib/crypto_backend/pbkdf2_generic.c
|
||||
*
|
||||
* under LGPLv2.1+ license
|
||||
*/
|
||||
static QCryptoPbkdfTestData test_data[] = {
|
||||
/* RFC 3962 test data */
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter1",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 1,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "ATHENA.MIT.EDUraeburn",
|
||||
.nsalt = 21,
|
||||
.out = "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01"
|
||||
"\x56\x5a\x11\x22\xb2\x56\x35\x15"
|
||||
"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3"
|
||||
"\x33\xec\xc0\xe2\xe1\xf7\x08\x37",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter2",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 2,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "ATHENA.MIT.EDUraeburn",
|
||||
.nsalt = 21,
|
||||
.out = "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e"
|
||||
"\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
|
||||
"\xa0\x53\x78\xb9\x32\x44\xec\x8f"
|
||||
"\x48\xa9\x9e\x61\xad\x79\x9d\x86",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200a",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 1200,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "ATHENA.MIT.EDUraeburn",
|
||||
.nsalt = 21,
|
||||
.out = "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e"
|
||||
"\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
|
||||
"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f"
|
||||
"\x70\x8a\x31\xe2\xe6\x2b\x1e\x13",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter5",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 5,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "\0224VxxV4\022", /* "\x1234567878563412 */
|
||||
.nsalt = 8,
|
||||
.out = "\xd1\xda\xa7\x86\x15\xf2\x87\xe6"
|
||||
"\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
|
||||
"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6"
|
||||
"\xad\xf4\xfa\x57\x4b\x6e\x64\xee",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200b",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 1200,
|
||||
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
.nkey = 64,
|
||||
.salt = "pass phrase equals block size",
|
||||
.nsalt = 29,
|
||||
.out = "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b"
|
||||
"\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
|
||||
"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc"
|
||||
"\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200c",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 1200,
|
||||
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
.nkey = 65,
|
||||
.salt = "pass phrase exceeds block size",
|
||||
.nsalt = 30,
|
||||
.out = "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5"
|
||||
"\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
|
||||
"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b"
|
||||
"\x36\xbe\x92\x46\x91\x5e\xc8\x2a",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc3962/sha1/iter50",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 50,
|
||||
.key = "\360\235\204\236", /* g-clef ("\xf09d849e) */
|
||||
.nkey = 4,
|
||||
.salt = "EXAMPLE.COMpianist",
|
||||
.nsalt = 18,
|
||||
.out = "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43"
|
||||
"\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
|
||||
"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2"
|
||||
"\x81\xff\x30\x69\xe1\xe9\x4f\x52",
|
||||
.nout = 32
|
||||
},
|
||||
|
||||
/* RFC-6070 test data */
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter1",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 1,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "salt",
|
||||
.nsalt = 4,
|
||||
.out = "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
|
||||
"\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6",
|
||||
.nout = 20
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter2",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 2,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "salt",
|
||||
.nsalt = 4,
|
||||
.out = "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
|
||||
"\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57",
|
||||
.nout = 20
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 4096,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "salt",
|
||||
.nsalt = 4,
|
||||
.out = "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
|
||||
"\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1",
|
||||
.nout = 20
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter16777216",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 16777216,
|
||||
.key = "password",
|
||||
.nkey = 8,
|
||||
.salt = "salt",
|
||||
.nsalt = 4,
|
||||
.out = "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
|
||||
"\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84",
|
||||
.nout = 20,
|
||||
.slow = true,
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096a",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 4096,
|
||||
.key = "passwordPASSWORDpassword",
|
||||
.nkey = 24,
|
||||
.salt = "saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
||||
.nsalt = 36,
|
||||
.out = "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
|
||||
"\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
|
||||
"\x4c\xf2\xf0\x70\x38",
|
||||
.nout = 25
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096b",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 4096,
|
||||
.key = "pass\0word",
|
||||
.nkey = 9,
|
||||
.salt = "sa\0lt",
|
||||
.nsalt = 5,
|
||||
.out = "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
|
||||
"\xd7\xf0\x34\x25\xe0\xc3",
|
||||
.nout = 16
|
||||
},
|
||||
|
||||
/* non-RFC misc test data */
|
||||
#ifdef CONFIG_NETTLE
|
||||
{
|
||||
/* empty password test.
|
||||
* Broken with libgcrypt <= 1.5.0, hence CONFIG_NETTLE */
|
||||
.path = "/crypto/pbkdf/nonrfc/sha1/iter2",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA1,
|
||||
.iterations = 2,
|
||||
.key = "",
|
||||
.nkey = 0,
|
||||
.salt = "salt",
|
||||
.nsalt = 4,
|
||||
.out = "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
|
||||
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97",
|
||||
.nout = 20
|
||||
},
|
||||
#endif
|
||||
{
|
||||
/* Password exceeds block size test */
|
||||
.path = "/crypto/pbkdf/nonrfc/sha256/iter1200",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA256,
|
||||
.iterations = 1200,
|
||||
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
.nkey = 65,
|
||||
.salt = "pass phrase exceeds block size",
|
||||
.nsalt = 30,
|
||||
.out = "\x22\x34\x4b\xc4\xb6\xe3\x26\x75"
|
||||
"\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d"
|
||||
"\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa"
|
||||
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58",
|
||||
.nout = 32
|
||||
},
|
||||
#if 0
|
||||
{
|
||||
.path = "/crypto/pbkdf/nonrfc/sha512/iter1200",
|
||||
.hash = QCRYPTO_HASH_ALG_SHA512,
|
||||
.iterations = 1200,
|
||||
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
.nkey = 129,
|
||||
.salt = "pass phrase exceeds block size",
|
||||
.nsalt = 30,
|
||||
.out = "\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d"
|
||||
"\x7d\x8e\xdd\x58\x01\xb4\x59\x72"
|
||||
"\x99\x92\x16\x30\x5e\xa4\x36\x8d"
|
||||
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9",
|
||||
.nout = 32
|
||||
},
|
||||
{
|
||||
.path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",
|
||||
.hash = QCRYPTO_HASH_ALG_WHIRLPOOL,
|
||||
.iterations = 1200,
|
||||
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
.nkey = 65,
|
||||
.salt = "pass phrase exceeds block size",
|
||||
.nsalt = 30,
|
||||
.out = "\x9c\x1c\x74\xf5\x88\x26\xe7\x6a"
|
||||
"\x53\x58\xf4\x0c\x39\xe7\x80\x89"
|
||||
"\x07\xc0\x31\x19\x9a\x50\xa2\x48"
|
||||
"\xf1\xd9\xfe\x78\x64\xe5\x84\x50",
|
||||
.nout = 32
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static inline char hex(int i)
|
||||
{
|
||||
if (i < 10) {
|
||||
return '0' + i;
|
||||
}
|
||||
return 'a' + (i - 10);
|
||||
}
|
||||
|
||||
static char *hex_string(const uint8_t *bytes,
|
||||
size_t len)
|
||||
{
|
||||
char *hexstr = g_new0(char, len * 2 + 1);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
hexstr[i * 2] = hex((bytes[i] >> 4) & 0xf);
|
||||
hexstr[i * 2 + 1] = hex(bytes[i] & 0xf);
|
||||
}
|
||||
hexstr[len * 2] = '\0';
|
||||
|
||||
return hexstr;
|
||||
}
|
||||
|
||||
static void test_pbkdf(const void *opaque)
|
||||
{
|
||||
const QCryptoPbkdfTestData *data = opaque;
|
||||
size_t nout = data->nout;
|
||||
uint8_t *out = g_new0(uint8_t, nout);
|
||||
gchar *expect, *actual;
|
||||
|
||||
qcrypto_pbkdf2(data->hash,
|
||||
(uint8_t *)data->key, data->nkey,
|
||||
(uint8_t *)data->salt, data->nsalt,
|
||||
data->iterations,
|
||||
(uint8_t *)out, nout,
|
||||
&error_abort);
|
||||
|
||||
expect = hex_string((const uint8_t *)data->out, data->nout);
|
||||
actual = hex_string(out, nout);
|
||||
|
||||
g_assert_cmpstr(actual, ==, expect);
|
||||
|
||||
g_free(actual);
|
||||
g_free(expect);
|
||||
g_free(out);
|
||||
}
|
||||
|
||||
|
||||
static void test_pbkdf_timing(void)
|
||||
{
|
||||
uint8_t key[32];
|
||||
uint8_t salt[32];
|
||||
int iters;
|
||||
|
||||
memset(key, 0x5d, sizeof(key));
|
||||
memset(salt, 0x7c, sizeof(salt));
|
||||
|
||||
iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
|
||||
key, sizeof(key),
|
||||
salt, sizeof(salt),
|
||||
&error_abort);
|
||||
|
||||
g_assert(iters >= (1 << 15));
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
if (!test_data[i].slow ||
|
||||
g_test_slow()) {
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_pbkdf);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_test_slow()) {
|
||||
g_test_add_func("/crypt0/pbkdf/timing", test_pbkdf_timing);
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
#else
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/init.h"
|
||||
#include "crypto/xts.h"
|
||||
#include "crypto/aes.h"
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
int keylen;
|
||||
unsigned char key1[32];
|
||||
unsigned char key2[32];
|
||||
uint64_t seqnum;
|
||||
unsigned long PTLEN;
|
||||
unsigned char PTX[512], CTX[512];
|
||||
} QCryptoXTSTestData;
|
||||
|
||||
static const QCryptoXTSTestData test_data[] = {
|
||||
/* #1 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-1-key-32-ptx-32",
|
||||
32,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
0,
|
||||
32,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
|
||||
0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
|
||||
0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
|
||||
0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e },
|
||||
},
|
||||
|
||||
/* #2, 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-2-key-32-ptx-32",
|
||||
32,
|
||||
{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 },
|
||||
{ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
|
||||
0x3333333333LL,
|
||||
32,
|
||||
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
|
||||
{ 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
|
||||
0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
|
||||
0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
|
||||
0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 },
|
||||
},
|
||||
|
||||
/* #5 from xts.7, 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-5-key-32-ptx-32",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
32,
|
||||
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
|
||||
{ 0xb0, 0x1f, 0x86, 0xf8, 0xed, 0xc1, 0x86, 0x37,
|
||||
0x06, 0xfa, 0x8a, 0x42, 0x53, 0xe3, 0x4f, 0x28,
|
||||
0xaf, 0x31, 0x9d, 0xe3, 0x83, 0x34, 0x87, 0x0f,
|
||||
0x4d, 0xd1, 0xf9, 0x4c, 0xbe, 0x98, 0x32, 0xf1 },
|
||||
},
|
||||
|
||||
/* #4, 32 byte key, 512 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-4-key-32-ptx-512",
|
||||
32,
|
||||
{ 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
|
||||
0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26 },
|
||||
{ 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
|
||||
0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 },
|
||||
0,
|
||||
512,
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
},
|
||||
{
|
||||
0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
|
||||
0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
|
||||
0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
|
||||
0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
|
||||
0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
|
||||
0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
|
||||
0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
|
||||
0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
|
||||
0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5,
|
||||
0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5,
|
||||
0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc,
|
||||
0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce,
|
||||
0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4,
|
||||
0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84,
|
||||
0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a,
|
||||
0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65,
|
||||
0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89,
|
||||
0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51,
|
||||
0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15,
|
||||
0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8,
|
||||
0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed,
|
||||
0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91,
|
||||
0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e,
|
||||
0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34,
|
||||
0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b,
|
||||
0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5,
|
||||
0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4,
|
||||
0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c,
|
||||
0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd,
|
||||
0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3,
|
||||
0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f,
|
||||
0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e,
|
||||
0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91,
|
||||
0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19,
|
||||
0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1,
|
||||
0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc,
|
||||
0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed,
|
||||
0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde,
|
||||
0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98,
|
||||
0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3,
|
||||
0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca,
|
||||
0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6,
|
||||
0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc,
|
||||
0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44,
|
||||
0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0,
|
||||
0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95,
|
||||
0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4,
|
||||
0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd,
|
||||
0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13,
|
||||
0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7,
|
||||
0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a,
|
||||
0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52,
|
||||
0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a,
|
||||
0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38,
|
||||
0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e,
|
||||
0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e,
|
||||
0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad,
|
||||
0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8,
|
||||
0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c,
|
||||
0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d,
|
||||
0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f,
|
||||
0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2,
|
||||
0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea,
|
||||
0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68,
|
||||
}
|
||||
},
|
||||
|
||||
/* #7, 32 byte key, 17 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-7-key-32-ptx-17",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
17,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
|
||||
{ 0x6c, 0x16, 0x25, 0xdb, 0x46, 0x71, 0x52, 0x2d,
|
||||
0x3d, 0x75, 0x99, 0x60, 0x1d, 0xe7, 0xca, 0x09, 0xed },
|
||||
},
|
||||
|
||||
/* #15, 32 byte key, 25 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-15-key-32-ptx-25",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
25,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 },
|
||||
{ 0x8f, 0x4d, 0xcb, 0xad, 0x55, 0x55, 0x8d, 0x7b,
|
||||
0x4e, 0x01, 0xd9, 0x37, 0x9c, 0xd4, 0xea, 0x22,
|
||||
0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a, 0x73 },
|
||||
},
|
||||
|
||||
/* #21, 32 byte key, 31 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-21-key-32-ptx-31",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
31,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e },
|
||||
{ 0xd0, 0x5b, 0xc0, 0x90, 0xa8, 0xe0, 0x4f, 0x1b,
|
||||
0x3d, 0x3e, 0xcd, 0xd5, 0xba, 0xec, 0x0f, 0xd4,
|
||||
0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a,
|
||||
0x73, 0x06, 0xe6, 0x4b, 0xe5, 0xdd, 0x82 },
|
||||
},
|
||||
};
|
||||
|
||||
#define STORE64L(x, y) \
|
||||
do { \
|
||||
(y)[7] = (unsigned char)(((x) >> 56) & 255); \
|
||||
(y)[6] = (unsigned char)(((x) >> 48) & 255); \
|
||||
(y)[5] = (unsigned char)(((x) >> 40) & 255); \
|
||||
(y)[4] = (unsigned char)(((x) >> 32) & 255); \
|
||||
(y)[3] = (unsigned char)(((x) >> 24) & 255); \
|
||||
(y)[2] = (unsigned char)(((x) >> 16) & 255); \
|
||||
(y)[1] = (unsigned char)(((x) >> 8) & 255); \
|
||||
(y)[0] = (unsigned char)((x) & 255); \
|
||||
} while (0)
|
||||
|
||||
struct TestAES {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
|
||||
static void test_xts_aes_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const struct TestAES *aesctx = ctx;
|
||||
|
||||
AES_encrypt(src, dst, &aesctx->enc);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts_aes_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const struct TestAES *aesctx = ctx;
|
||||
|
||||
AES_decrypt(src, dst, &aesctx->dec);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts(const void *opaque)
|
||||
{
|
||||
const QCryptoXTSTestData *data = opaque;
|
||||
unsigned char OUT[512], Torg[16], T[16];
|
||||
uint64_t seq;
|
||||
int j;
|
||||
unsigned long len;
|
||||
struct TestAES aesdata;
|
||||
struct TestAES aestweak;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
/* skip the cases where
|
||||
* the length is smaller than 2*blocklen
|
||||
* or the length is not a multiple of 32
|
||||
*/
|
||||
if ((j == 1) && ((data->PTLEN < 32) || (data->PTLEN % 32))) {
|
||||
continue;
|
||||
}
|
||||
len = data->PTLEN / 2;
|
||||
|
||||
AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
|
||||
AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
|
||||
AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
|
||||
AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
|
||||
|
||||
seq = data->seqnum;
|
||||
STORE64L(seq, Torg);
|
||||
memset(Torg + 8, 0, 8);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
if (j == 0) {
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, OUT, data->PTX);
|
||||
} else {
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, OUT, data->PTX);
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, &OUT[len], &data->PTX[len]);
|
||||
}
|
||||
|
||||
g_assert(memcmp(OUT, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
if (j == 0) {
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, OUT, data->CTX);
|
||||
} else {
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, OUT, data->CTX);
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, &OUT[len], &data->CTX[len]);
|
||||
}
|
||||
|
||||
g_assert(memcmp(OUT, data->PTX, data->PTLEN) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
g_test_add_data_func(test_data[i].path, &test_data[i], test_xts);
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
Loading…
Reference in New Issue