mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
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
45 changed files with 6487 additions and 108 deletions
|
@ -1,6 +1,6 @@
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# Common libraries for tools and emulators
|
# Common libraries for tools and emulators
|
||||||
stub-obj-y = stubs/
|
stub-obj-y = stubs/ crypto/
|
||||||
util-obj-y = util/ qobject/ qapi/
|
util-obj-y = util/ qobject/ qapi/
|
||||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
||||||
|
|
||||||
|
|
32
configure
vendored
32
configure
vendored
|
@ -306,8 +306,10 @@ gtkabi=""
|
||||||
gtk_gl="no"
|
gtk_gl="no"
|
||||||
gnutls=""
|
gnutls=""
|
||||||
gnutls_hash=""
|
gnutls_hash=""
|
||||||
|
gnutls_rnd=""
|
||||||
nettle=""
|
nettle=""
|
||||||
gcrypt=""
|
gcrypt=""
|
||||||
|
gcrypt_kdf="no"
|
||||||
vte=""
|
vte=""
|
||||||
virglrenderer=""
|
virglrenderer=""
|
||||||
tpm="yes"
|
tpm="yes"
|
||||||
|
@ -2201,6 +2203,13 @@ if test "$gnutls" != "no"; then
|
||||||
gnutls_hash="no"
|
gnutls_hash="no"
|
||||||
fi
|
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
|
if $pkg_config --exists 'gnutls >= 3.0'; then
|
||||||
gnutls_gcrypt=no
|
gnutls_gcrypt=no
|
||||||
gnutls_nettle=yes
|
gnutls_nettle=yes
|
||||||
|
@ -2228,9 +2237,11 @@ if test "$gnutls" != "no"; then
|
||||||
else
|
else
|
||||||
gnutls="no"
|
gnutls="no"
|
||||||
gnutls_hash="no"
|
gnutls_hash="no"
|
||||||
|
gnutls_rnd="no"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
gnutls_hash="no"
|
gnutls_hash="no"
|
||||||
|
gnutls_rnd="no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
@ -2292,6 +2303,19 @@ if test "$gcrypt" != "no"; then
|
||||||
if test -z "$nettle"; then
|
if test -z "$nettle"; then
|
||||||
nettle="no"
|
nettle="no"
|
||||||
fi
|
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
|
else
|
||||||
if test "$gcrypt" = "yes"; then
|
if test "$gcrypt" = "yes"; then
|
||||||
feature_not_found "gcrypt" "Install gcrypt devel"
|
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||||
|
@ -4714,7 +4738,9 @@ echo "GTK support $gtk"
|
||||||
echo "GTK GL support $gtk_gl"
|
echo "GTK GL support $gtk_gl"
|
||||||
echo "GNUTLS support $gnutls"
|
echo "GNUTLS support $gnutls"
|
||||||
echo "GNUTLS hash $gnutls_hash"
|
echo "GNUTLS hash $gnutls_hash"
|
||||||
|
echo "GNUTLS rnd $gnutls_rnd"
|
||||||
echo "libgcrypt $gcrypt"
|
echo "libgcrypt $gcrypt"
|
||||||
|
echo "libgcrypt kdf $gcrypt_kdf"
|
||||||
if test "$nettle" = "yes"; then
|
if test "$nettle" = "yes"; then
|
||||||
echo "nettle $nettle ($nettle_version)"
|
echo "nettle $nettle ($nettle_version)"
|
||||||
else
|
else
|
||||||
|
@ -5092,8 +5118,14 @@ fi
|
||||||
if test "$gnutls_hash" = "yes" ; then
|
if test "$gnutls_hash" = "yes" ; then
|
||||||
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$gnutls_rnd" = "yes" ; then
|
||||||
|
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$gcrypt" = "yes" ; then
|
if test "$gcrypt" = "yes" ; then
|
||||||
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
||||||
|
if test "$gcrypt_kdf" = "yes" ; then
|
||||||
|
echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if test "$nettle" = "yes" ; then
|
if test "$nettle" = "yes" ; then
|
||||||
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||||||
|
|
|
@ -8,6 +8,23 @@ crypto-obj-y += tlscredsanon.o
|
||||||
crypto-obj-y += tlscredsx509.o
|
crypto-obj-y += tlscredsx509.o
|
||||||
crypto-obj-y += tlssession.o
|
crypto-obj-y += tlssession.o
|
||||||
crypto-obj-y += secret.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
|
# Let the userspace emulators avoid linking gnutls/etc
|
||||||
crypto-aes-obj-y = aes.o
|
crypto-aes-obj-y = aes.o
|
||||||
|
|
||||||
|
stub-obj-y += random-stub.o
|
||||||
|
stub-obj-y += pbkdf-stub.o
|
||||||
|
|
158
crypto/afsplit.c
Normal file
158
crypto/afsplit.c
Normal file
|
@ -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;
|
||||||
|
}
|
1328
crypto/block-luks.c
Normal file
1328
crypto/block-luks.c
Normal file
File diff suppressed because it is too large
Load diff
28
crypto/block-luks.h
Normal file
28
crypto/block-luks.h
Normal file
|
@ -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__ */
|
173
crypto/block-qcow.c
Normal file
173
crypto/block-qcow.c
Normal file
|
@ -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,
|
||||||
|
};
|
28
crypto/block-qcow.h
Normal file
28
crypto/block-qcow.h
Normal file
|
@ -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__ */
|
260
crypto/block.c
Normal file
260
crypto/block.c
Normal file
|
@ -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;
|
||||||
|
}
|
92
crypto/blockpriv.h
Normal file
92
crypto/blockpriv.h
Normal file
|
@ -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 "qemu/osdep.h"
|
||||||
#include "crypto/aes.h"
|
#include "crypto/aes.h"
|
||||||
#include "crypto/desrfb.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;
|
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||||
struct QCryptoCipherBuiltinAES {
|
struct QCryptoCipherBuiltinAES {
|
||||||
AES_KEY encrypt_key;
|
QCryptoCipherBuiltinAESContext key;
|
||||||
AES_KEY decrypt_key;
|
QCryptoCipherBuiltinAESContext key_tweak;
|
||||||
uint8_t iv[AES_BLOCK_SIZE];
|
uint8_t iv[AES_BLOCK_SIZE];
|
||||||
};
|
};
|
||||||
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||||
|
@ -67,20 +73,16 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
|
||||||
const void *in,
|
const void *in,
|
||||||
void *out,
|
void *out,
|
||||||
size_t len,
|
size_t len)
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
|
||||||
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
|
||||||
const uint8_t *inptr = in;
|
const uint8_t *inptr = in;
|
||||||
uint8_t *outptr = out;
|
uint8_t *outptr = out;
|
||||||
while (len) {
|
while (len) {
|
||||||
if (len > AES_BLOCK_SIZE) {
|
if (len > AES_BLOCK_SIZE) {
|
||||||
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
AES_encrypt(inptr, outptr, key);
|
||||||
inptr += AES_BLOCK_SIZE;
|
inptr += AES_BLOCK_SIZE;
|
||||||
outptr += AES_BLOCK_SIZE;
|
outptr += AES_BLOCK_SIZE;
|
||||||
len -= AES_BLOCK_SIZE;
|
len -= AES_BLOCK_SIZE;
|
||||||
|
@ -89,15 +91,92 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||||
memcpy(tmp1, inptr, len);
|
memcpy(tmp1, inptr, len);
|
||||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||||
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
AES_encrypt(tmp1, tmp2, key);
|
||||||
memcpy(outptr, tmp2, len);
|
memcpy(outptr, tmp2, len);
|
||||||
len = 0;
|
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 {
|
} 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,
|
||||||
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
|
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,
|
AES_cbc_encrypt(in, out, len,
|
||||||
&ctxt->state.aes.encrypt_key,
|
&ctxt->state.aes.key.enc,
|
||||||
ctxt->state.aes.iv, 1);
|
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;
|
return 0;
|
||||||
|
@ -112,29 +191,26 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||||
{
|
{
|
||||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||||
|
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
switch (cipher->mode) {
|
||||||
const uint8_t *inptr = in;
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
uint8_t *outptr = out;
|
qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
|
||||||
while (len) {
|
in, out, len);
|
||||||
if (len > AES_BLOCK_SIZE) {
|
break;
|
||||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
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 {
|
|
||||||
AES_cbc_encrypt(in, out, len,
|
AES_cbc_encrypt(in, out, len,
|
||||||
&ctxt->state.aes.decrypt_key,
|
&ctxt->state.aes.key.dec,
|
||||||
ctxt->state.aes.iv, 0);
|
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;
|
return 0;
|
||||||
|
@ -166,23 +242,48 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
||||||
QCryptoCipherBuiltin *ctxt;
|
QCryptoCipherBuiltin *ctxt;
|
||||||
|
|
||||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
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);
|
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||||
|
|
||||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
|
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");
|
error_setg(errp, "Failed to set encryption key");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
|
if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
|
||||||
error_setg(errp, "Failed to set decryption key");
|
error_setg(errp, "Failed to set decryption key");
|
||||||
goto error;
|
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;
|
ctxt->blocksize = AES_BLOCK_SIZE;
|
||||||
ctxt->free = qcrypto_cipher_free_aes;
|
ctxt->free = qcrypto_cipher_free_aes;
|
||||||
ctxt->setiv = qcrypto_cipher_setiv_aes;
|
ctxt->setiv = qcrypto_cipher_setiv_aes;
|
||||||
|
@ -322,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
cipher->alg = alg;
|
cipher->alg = alg;
|
||||||
cipher->mode = mode;
|
cipher->mode = mode;
|
||||||
|
|
||||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/xts.h"
|
||||||
|
|
||||||
#include <gcrypt.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_128:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
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;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -38,7 +46,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||||
struct QCryptoCipherGcrypt {
|
struct QCryptoCipherGcrypt {
|
||||||
gcry_cipher_hd_t handle;
|
gcry_cipher_hd_t handle;
|
||||||
|
gcry_cipher_hd_t tweakhandle;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
|
uint8_t *iv;
|
||||||
};
|
};
|
||||||
|
|
||||||
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
@ -53,6 +63,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||||
break;
|
break;
|
||||||
case QCRYPTO_CIPHER_MODE_CBC:
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
@ -63,7 +74,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +95,30 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
gcryalg = GCRY_CIPHER_AES256;
|
gcryalg = GCRY_CIPHER_AES256;
|
||||||
break;
|
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:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -101,6 +136,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
goto error;
|
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) {
|
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||||
/* We're using standard DES cipher from gcrypt, so we need
|
/* We're using standard DES cipher from gcrypt, so we need
|
||||||
|
@ -111,21 +154,55 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
|
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
|
||||||
g_free(rfbkey);
|
g_free(rfbkey);
|
||||||
ctx->blocksize = 8;
|
ctx->blocksize = 8;
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||||
ctx->blocksize = 16;
|
|
||||||
}
|
}
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
error_setg(errp, "Cannot set key: %s",
|
error_setg(errp, "Cannot set key: %s",
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
goto error;
|
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 (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
|
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
cipher->opaque = ctx;
|
cipher->opaque = ctx;
|
||||||
return cipher;
|
return cipher;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
gcry_cipher_close(ctx->handle);
|
gcry_cipher_close(ctx->handle);
|
||||||
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
|
gcry_cipher_close(ctx->tweakhandle);
|
||||||
|
}
|
||||||
g_free(ctx);
|
g_free(ctx);
|
||||||
g_free(cipher);
|
g_free(cipher);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -140,11 +217,35 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||||
}
|
}
|
||||||
ctx = cipher->opaque;
|
ctx = cipher->opaque;
|
||||||
gcry_cipher_close(ctx->handle);
|
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(ctx);
|
||||||
g_free(cipher);
|
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,
|
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
const void *in,
|
const void *in,
|
||||||
void *out,
|
void *out,
|
||||||
|
@ -160,6 +261,12 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
return -1;
|
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,
|
err = gcry_cipher_encrypt(ctx->handle,
|
||||||
out, len,
|
out, len,
|
||||||
in, len);
|
in, len);
|
||||||
|
@ -168,6 +275,7 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +296,12 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
return -1;
|
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,
|
err = gcry_cipher_decrypt(ctx->handle,
|
||||||
out, len,
|
out, len,
|
||||||
in, len);
|
in, len);
|
||||||
|
@ -196,6 +310,7 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +328,9 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->iv) {
|
||||||
|
memcpy(ctx->iv, iv, niv);
|
||||||
|
} else {
|
||||||
gcry_cipher_reset(ctx->handle);
|
gcry_cipher_reset(ctx->handle);
|
||||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -220,6 +338,7 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/xts.h"
|
||||||
|
|
||||||
#include <nettle/nettle-types.h>
|
#include <nettle/nettle-types.h>
|
||||||
#include <nettle/aes.h>
|
#include <nettle/aes.h>
|
||||||
#include <nettle/des.h>
|
#include <nettle/des.h>
|
||||||
#include <nettle/cbc.h>
|
#include <nettle/cbc.h>
|
||||||
|
#include <nettle/cast128.h>
|
||||||
|
#include <nettle/serpent.h>
|
||||||
|
#include <nettle/twofish.h>
|
||||||
|
|
||||||
#if CONFIG_NETTLE_VERSION_MAJOR < 3
|
#if CONFIG_NETTLE_VERSION_MAJOR < 3
|
||||||
typedef nettle_crypt_func nettle_cipher_func;
|
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_encrypt_wrapper;
|
||||||
static nettle_cipher_func des_decrypt_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,
|
static void aes_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||||
uint8_t *dst, const uint8_t *src)
|
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,
|
static void aes_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||||
uint8_t *dst, const uint8_t *src)
|
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,
|
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);
|
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;
|
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
|
||||||
struct QCryptoCipherNettle {
|
struct QCryptoCipherNettle {
|
||||||
void *ctx_encrypt;
|
/* Primary cipher context for all modes */
|
||||||
void *ctx_decrypt;
|
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_encrypt;
|
||||||
nettle_cipher_func *alg_decrypt;
|
nettle_cipher_func *alg_decrypt;
|
||||||
|
|
||||||
uint8_t *iv;
|
uint8_t *iv;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
};
|
};
|
||||||
|
@ -80,6 +132,13 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
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;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,13 +158,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
case QCRYPTO_CIPHER_MODE_CBC:
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,10 +177,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||||
|
|
||||||
switch (alg) {
|
switch (alg) {
|
||||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||||
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
|
ctx->ctx = g_new0(struct des_ctx, 1);
|
||||||
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
|
|
||||||
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
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);
|
g_free(rfbkey);
|
||||||
|
|
||||||
ctx->alg_encrypt = des_encrypt_wrapper;
|
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_128:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||||
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
|
ctx->ctx = g_new0(QCryptoNettleAES, 1);
|
||||||
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
|
|
||||||
|
|
||||||
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
|
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_encrypt = aes_encrypt_wrapper;
|
||||||
ctx->alg_decrypt = aes_decrypt_wrapper;
|
ctx->alg_decrypt = aes_decrypt_wrapper;
|
||||||
|
|
||||||
ctx->blocksize = AES_BLOCK_SIZE;
|
ctx->blocksize = AES_BLOCK_SIZE;
|
||||||
break;
|
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:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -170,8 +307,8 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||||
|
|
||||||
ctx = cipher->opaque;
|
ctx = cipher->opaque;
|
||||||
g_free(ctx->iv);
|
g_free(ctx->iv);
|
||||||
g_free(ctx->ctx_encrypt);
|
g_free(ctx->ctx);
|
||||||
g_free(ctx->ctx_decrypt);
|
g_free(ctx->ctx_tweak);
|
||||||
g_free(ctx);
|
g_free(ctx);
|
||||||
g_free(cipher);
|
g_free(cipher);
|
||||||
}
|
}
|
||||||
|
@ -193,14 +330,21 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
|
|
||||||
switch (cipher->mode) {
|
switch (cipher->mode) {
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
|
ctx->alg_encrypt(ctx->ctx, len, out, in);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_CBC:
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
|
cbc_encrypt(ctx->ctx, ctx->alg_encrypt,
|
||||||
ctx->blocksize, ctx->iv,
|
ctx->blocksize, ctx->iv,
|
||||||
len, out, in);
|
len, out, in);
|
||||||
break;
|
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:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||||
cipher->alg);
|
cipher->alg);
|
||||||
|
@ -226,15 +370,26 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
|
|
||||||
switch (cipher->mode) {
|
switch (cipher->mode) {
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
ctx->alg_decrypt(ctx->ctx, len, out, in);
|
||||||
len, out, in);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_CBC:
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
cbc_decrypt(ctx->ctx, ctx->alg_decrypt,
|
||||||
ctx->alg_decrypt, ctx->blocksize, ctx->iv,
|
ctx->blocksize, ctx->iv,
|
||||||
len, out, in);
|
len, out, in);
|
||||||
break;
|
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:
|
default:
|
||||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||||
cipher->alg);
|
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_192] = 24,
|
||||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
[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] = {
|
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_192] = 16,
|
||||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
[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] = {
|
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||||
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
||||||
[QCRYPTO_CIPHER_MODE_CBC] = true,
|
[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
|
static bool
|
||||||
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||||
|
QCryptoCipherMode mode,
|
||||||
size_t nkey,
|
size_t nkey,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -88,11 +104,28 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||||
return false;
|
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) {
|
if (alg_key_len[alg] != nkey) {
|
||||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||||
nkey, alg_key_len[alg]);
|
nkey, alg_key_len[alg]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
118
crypto/ivgen-essiv.c
Normal file
118
crypto/ivgen-essiv.c
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - essiv
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/ivgen-essiv.h"
|
||||||
|
|
||||||
|
typedef struct QCryptoIVGenESSIV QCryptoIVGenESSIV;
|
||||||
|
struct QCryptoIVGenESSIV {
|
||||||
|
QCryptoCipher *cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
uint8_t *salt;
|
||||||
|
size_t nhash;
|
||||||
|
size_t nsalt;
|
||||||
|
QCryptoIVGenESSIV *essiv = g_new0(QCryptoIVGenESSIV, 1);
|
||||||
|
|
||||||
|
/* Not necessarily the same as nkey */
|
||||||
|
nsalt = qcrypto_cipher_get_key_len(ivgen->cipher);
|
||||||
|
|
||||||
|
nhash = qcrypto_hash_digest_len(ivgen->hash);
|
||||||
|
/* Salt must be larger of hash size or key size */
|
||||||
|
salt = g_new0(uint8_t, MAX(nhash, nsalt));
|
||||||
|
|
||||||
|
if (qcrypto_hash_bytes(ivgen->hash, (const gchar *)key, nkey,
|
||||||
|
&salt, &nhash,
|
||||||
|
errp) < 0) {
|
||||||
|
g_free(essiv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now potentially truncate salt to match cipher key len */
|
||||||
|
essiv->cipher = qcrypto_cipher_new(ivgen->cipher,
|
||||||
|
QCRYPTO_CIPHER_MODE_ECB,
|
||||||
|
salt, MIN(nhash, nsalt),
|
||||||
|
errp);
|
||||||
|
if (!essiv->cipher) {
|
||||||
|
g_free(essiv);
|
||||||
|
g_free(salt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(salt);
|
||||||
|
ivgen->private = essiv;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_essiv_calculate(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||||
|
size_t ndata = qcrypto_cipher_get_block_len(ivgen->cipher);
|
||||||
|
uint8_t *data = g_new(uint8_t, ndata);
|
||||||
|
|
||||||
|
sector = cpu_to_le64(sector);
|
||||||
|
memcpy(data, (uint8_t *)§or, ndata);
|
||||||
|
if (sizeof(sector) < ndata) {
|
||||||
|
memset(data + sizeof(sector), 0, ndata - sizeof(sector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qcrypto_cipher_encrypt(essiv->cipher,
|
||||||
|
data,
|
||||||
|
data,
|
||||||
|
ndata,
|
||||||
|
errp) < 0) {
|
||||||
|
g_free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ndata > niv) {
|
||||||
|
ndata = niv;
|
||||||
|
}
|
||||||
|
memcpy(iv, data, ndata);
|
||||||
|
if (ndata < niv) {
|
||||||
|
memset(iv + ndata, 0, niv - ndata);
|
||||||
|
}
|
||||||
|
g_free(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_ivgen_essiv_cleanup(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||||
|
|
||||||
|
qcrypto_cipher_free(essiv->cipher);
|
||||||
|
g_free(essiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct QCryptoIVGenDriver qcrypto_ivgen_essiv = {
|
||||||
|
.init = qcrypto_ivgen_essiv_init,
|
||||||
|
.calculate = qcrypto_ivgen_essiv_calculate,
|
||||||
|
.cleanup = qcrypto_ivgen_essiv_cleanup,
|
||||||
|
};
|
||||||
|
|
28
crypto/ivgen-essiv.h
Normal file
28
crypto/ivgen-essiv.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - essiv
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/ivgenpriv.h"
|
||||||
|
|
||||||
|
#ifndef QCRYPTO_IVGEN_ESSIV_H__
|
||||||
|
#define QCRYPTO_IVGEN_ESSIV_H__
|
||||||
|
|
||||||
|
extern struct QCryptoIVGenDriver qcrypto_ivgen_essiv;
|
||||||
|
|
||||||
|
#endif /* QCRYPTO_IVGEN_ESSIV_H__ */
|
59
crypto/ivgen-plain.c
Normal file
59
crypto/ivgen-plain.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - plain
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/ivgen-plain.h"
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
size_t ivprefix;
|
||||||
|
uint32_t shortsector = cpu_to_le32((sector & 0xffffffff));
|
||||||
|
ivprefix = sizeof(shortsector);
|
||||||
|
if (ivprefix > niv) {
|
||||||
|
ivprefix = niv;
|
||||||
|
}
|
||||||
|
memcpy(iv, &shortsector, ivprefix);
|
||||||
|
if (ivprefix < niv) {
|
||||||
|
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct QCryptoIVGenDriver qcrypto_ivgen_plain = {
|
||||||
|
.init = qcrypto_ivgen_plain_init,
|
||||||
|
.calculate = qcrypto_ivgen_plain_calculate,
|
||||||
|
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||||
|
};
|
||||||
|
|
28
crypto/ivgen-plain.h
Normal file
28
crypto/ivgen-plain.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - plain
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/ivgenpriv.h"
|
||||||
|
|
||||||
|
#ifndef QCRYPTO_IVGEN_PLAIN_H__
|
||||||
|
#define QCRYPTO_IVGEN_PLAIN_H__
|
||||||
|
|
||||||
|
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain;
|
||||||
|
|
||||||
|
#endif /* QCRYPTO_IVGEN_PLAIN_H__ */
|
59
crypto/ivgen-plain64.c
Normal file
59
crypto/ivgen-plain64.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - plain
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/ivgen-plain.h"
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
size_t ivprefix;
|
||||||
|
ivprefix = sizeof(sector);
|
||||||
|
sector = cpu_to_le64(sector);
|
||||||
|
if (ivprefix > niv) {
|
||||||
|
ivprefix = niv;
|
||||||
|
}
|
||||||
|
memcpy(iv, §or, ivprefix);
|
||||||
|
if (ivprefix < niv) {
|
||||||
|
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct QCryptoIVGenDriver qcrypto_ivgen_plain64 = {
|
||||||
|
.init = qcrypto_ivgen_plain_init,
|
||||||
|
.calculate = qcrypto_ivgen_plain_calculate,
|
||||||
|
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||||
|
};
|
||||||
|
|
28
crypto/ivgen-plain64.h
Normal file
28
crypto/ivgen-plain64.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator - plain64
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto/ivgenpriv.h"
|
||||||
|
|
||||||
|
#ifndef QCRYPTO_IVGEN_PLAIN64_H__
|
||||||
|
#define QCRYPTO_IVGEN_PLAIN64_H__
|
||||||
|
|
||||||
|
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain64;
|
||||||
|
|
||||||
|
#endif /* QCRYPTO_IVGEN_PLAIN64_H__ */
|
99
crypto/ivgen.c
Normal file
99
crypto/ivgen.c
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/ivgenpriv.h"
|
||||||
|
#include "crypto/ivgen-plain.h"
|
||||||
|
#include "crypto/ivgen-plain64.h"
|
||||||
|
#include "crypto/ivgen-essiv.h"
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
|
||||||
|
QCryptoCipherAlgorithm cipheralg,
|
||||||
|
QCryptoHashAlgorithm hash,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoIVGen *ivgen = g_new0(QCryptoIVGen, 1);
|
||||||
|
|
||||||
|
ivgen->algorithm = alg;
|
||||||
|
ivgen->cipher = cipheralg;
|
||||||
|
ivgen->hash = hash;
|
||||||
|
|
||||||
|
switch (alg) {
|
||||||
|
case QCRYPTO_IVGEN_ALG_PLAIN:
|
||||||
|
ivgen->driver = &qcrypto_ivgen_plain;
|
||||||
|
break;
|
||||||
|
case QCRYPTO_IVGEN_ALG_PLAIN64:
|
||||||
|
ivgen->driver = &qcrypto_ivgen_plain64;
|
||||||
|
break;
|
||||||
|
case QCRYPTO_IVGEN_ALG_ESSIV:
|
||||||
|
ivgen->driver = &qcrypto_ivgen_essiv;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_setg(errp, "Unknown block IV generator algorithm %d", alg);
|
||||||
|
g_free(ivgen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ivgen->driver->init(ivgen, key, nkey, errp) < 0) {
|
||||||
|
g_free(ivgen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ivgen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
return ivgen->driver->calculate(ivgen, sector, iv, niv, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
return ivgen->algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
return ivgen->cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
return ivgen->hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qcrypto_ivgen_free(QCryptoIVGen *ivgen)
|
||||||
|
{
|
||||||
|
if (!ivgen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ivgen->driver->cleanup(ivgen);
|
||||||
|
g_free(ivgen);
|
||||||
|
}
|
49
crypto/ivgenpriv.h
Normal file
49
crypto/ivgenpriv.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QCRYPTO_IVGEN_PRIV_H__
|
||||||
|
#define QCRYPTO_IVGEN_PRIV_H__
|
||||||
|
|
||||||
|
#include "crypto/ivgen.h"
|
||||||
|
|
||||||
|
typedef struct QCryptoIVGenDriver QCryptoIVGenDriver;
|
||||||
|
|
||||||
|
struct QCryptoIVGenDriver {
|
||||||
|
int (*init)(QCryptoIVGen *ivgen,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp);
|
||||||
|
int (*calculate)(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp);
|
||||||
|
void (*cleanup)(QCryptoIVGen *ivgen);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QCryptoIVGen {
|
||||||
|
QCryptoIVGenDriver *driver;
|
||||||
|
void *private;
|
||||||
|
|
||||||
|
QCryptoIVGenAlgorithm algorithm;
|
||||||
|
QCryptoCipherAlgorithm cipher;
|
||||||
|
QCryptoHashAlgorithm hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* QCRYPTO_IVGEN_PRIV_H__ */
|
68
crypto/pbkdf-gcrypt.c
Normal file
68
crypto/pbkdf-gcrypt.c
Normal file
|
@ -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;
|
||||||
|
}
|
65
crypto/pbkdf-nettle.c
Normal file
65
crypto/pbkdf-nettle.c
Normal file
|
@ -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;
|
||||||
|
}
|
42
crypto/pbkdf-stub.c
Normal file
42
crypto/pbkdf-stub.c
Normal file
|
@ -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;
|
||||||
|
}
|
109
crypto/pbkdf.c
Normal file
109
crypto/pbkdf.c
Normal file
|
@ -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;
|
||||||
|
}
|
33
crypto/random-gcrypt.c
Normal file
33
crypto/random-gcrypt.c
Normal file
|
@ -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;
|
||||||
|
}
|
43
crypto/random-gnutls.c
Normal file
43
crypto/random-gnutls.c
Normal file
|
@ -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;
|
||||||
|
}
|
31
crypto/random-stub.c
Normal file
31
crypto/random-stub.c
Normal file
|
@ -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;
|
||||||
|
}
|
230
crypto/xts.c
Normal file
230
crypto/xts.c
Normal file
|
@ -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);
|
||||||
|
}
|
135
include/crypto/afsplit.h
Normal file
135
include/crypto/afsplit.h
Normal file
|
@ -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__ */
|
232
include/crypto/block.h
Normal file
232
include/crypto/block.h
Normal file
|
@ -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__ */
|
206
include/crypto/ivgen.h
Normal file
206
include/crypto/ivgen.h
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto block IV generator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QCRYPTO_IVGEN_H__
|
||||||
|
#define QCRYPTO_IVGEN_H__
|
||||||
|
|
||||||
|
#include "crypto/cipher.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module provides a framework for generating initialization
|
||||||
|
* vectors for block encryption schemes using chained cipher modes
|
||||||
|
* CBC. The principle is that each disk sector is assigned a unique
|
||||||
|
* initialization vector for use for encryption of data in that
|
||||||
|
* sector.
|
||||||
|
*
|
||||||
|
* <example>
|
||||||
|
* <title>Encrypting block data with initialiation vectors</title>
|
||||||
|
* <programlisting>
|
||||||
|
* uint8_t *data = ....data to encrypt...
|
||||||
|
* size_t ndata = XXX;
|
||||||
|
* uint8_t *key = ....some encryption key...
|
||||||
|
* size_t nkey = XXX;
|
||||||
|
* uint8_t *iv;
|
||||||
|
* size_t niv;
|
||||||
|
* size_t sector = 0;
|
||||||
|
*
|
||||||
|
* g_assert((ndata % 512) == 0);
|
||||||
|
*
|
||||||
|
* QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV,
|
||||||
|
* QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
* QCRYPTO_HASH_ALG_SHA256,
|
||||||
|
* key, nkey, errp);
|
||||||
|
* if (!ivgen) {
|
||||||
|
* return -1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
* QCRYPTO_CIPHER_MODE_CBC,
|
||||||
|
* key, nkey, errp);
|
||||||
|
* if (!cipher) {
|
||||||
|
* goto error;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
* QCRYPTO_CIPHER_MODE_CBC);
|
||||||
|
* iv = g_new0(uint8_t, niv);
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* while (ndata) {
|
||||||
|
* if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) {
|
||||||
|
* goto error;
|
||||||
|
* }
|
||||||
|
* if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) {
|
||||||
|
* goto error;
|
||||||
|
* }
|
||||||
|
* if (qcrypto_cipher_encrypt(cipher,
|
||||||
|
* data + (sector * 512),
|
||||||
|
* data + (sector * 512),
|
||||||
|
* 512, errp) < 0) {
|
||||||
|
* goto error;
|
||||||
|
* }
|
||||||
|
* sector++;
|
||||||
|
* ndata -= 512;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* g_free(iv);
|
||||||
|
* qcrypto_ivgen_free(ivgen);
|
||||||
|
* qcrypto_cipher_free(cipher);
|
||||||
|
* return 0;
|
||||||
|
*
|
||||||
|
*error:
|
||||||
|
* g_free(iv);
|
||||||
|
* qcrypto_ivgen_free(ivgen);
|
||||||
|
* qcrypto_cipher_free(cipher);
|
||||||
|
* return -1;
|
||||||
|
* </programlisting>
|
||||||
|
* </example>
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct QCryptoIVGen QCryptoIVGen;
|
||||||
|
|
||||||
|
/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_new:
|
||||||
|
* @alg: the initialization vector generation algorithm
|
||||||
|
* @cipheralg: the cipher algorithm or 0
|
||||||
|
* @hash: the hash algorithm or 0
|
||||||
|
* @key: the encryption key or NULL
|
||||||
|
* @nkey: the size of @key in bytes
|
||||||
|
*
|
||||||
|
* Create a new initialization vector generator that uses
|
||||||
|
* the algorithm @alg. Whether the remaining parameters
|
||||||
|
* are required or not depends on the choice of @alg
|
||||||
|
* requested.
|
||||||
|
*
|
||||||
|
* - QCRYPTO_IVGEN_ALG_PLAIN
|
||||||
|
*
|
||||||
|
* The IVs are generated by the 32-bit truncated sector
|
||||||
|
* number. This should never be used for block devices
|
||||||
|
* that are larger than 2^32 sectors in size.
|
||||||
|
* All the other parameters are unused.
|
||||||
|
*
|
||||||
|
* - QCRYPTO_IVGEN_ALG_PLAIN64
|
||||||
|
*
|
||||||
|
* The IVs are generated by the 64-bit sector number.
|
||||||
|
* All the other parameters are unused.
|
||||||
|
*
|
||||||
|
* - QCRYPTO_IVGEN_ALG_ESSIV:
|
||||||
|
*
|
||||||
|
* The IVs are generated by encrypting the 64-bit sector
|
||||||
|
* number with a hash of an encryption key. The @cipheralg,
|
||||||
|
* @hash, @key and @nkey parameters are all required.
|
||||||
|
*
|
||||||
|
* Returns: a new IV generator, or NULL on error
|
||||||
|
*/
|
||||||
|
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
|
||||||
|
QCryptoCipherAlgorithm cipheralg,
|
||||||
|
QCryptoHashAlgorithm hash,
|
||||||
|
const uint8_t *key, size_t nkey,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_calculate:
|
||||||
|
* @ivgen: the IV generator object
|
||||||
|
* @sector: the 64-bit sector number
|
||||||
|
* @iv: a pre-allocated buffer to hold the generated IV
|
||||||
|
* @niv: the number of bytes in @iv
|
||||||
|
* @errp: pointer to a NULL-initialized error object
|
||||||
|
*
|
||||||
|
* Calculate a new initialiation vector for the data
|
||||||
|
* to be stored in sector @sector. The IV will be
|
||||||
|
* written into the buffer @iv of size @niv.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
|
||||||
|
uint64_t sector,
|
||||||
|
uint8_t *iv, size_t niv,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_get_algorithm:
|
||||||
|
* @ivgen: the IV generator object
|
||||||
|
*
|
||||||
|
* Get the algorithm used by this IV generator
|
||||||
|
*
|
||||||
|
* Returns: the IV generator algorithm
|
||||||
|
*/
|
||||||
|
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_get_cipher:
|
||||||
|
* @ivgen: the IV generator object
|
||||||
|
*
|
||||||
|
* Get the cipher algorithm used by this IV generator (if
|
||||||
|
* applicable)
|
||||||
|
*
|
||||||
|
* Returns: the cipher algorithm
|
||||||
|
*/
|
||||||
|
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_get_hash:
|
||||||
|
* @ivgen: the IV generator object
|
||||||
|
*
|
||||||
|
* Get the hash algorithm used by this IV generator (if
|
||||||
|
* applicable)
|
||||||
|
*
|
||||||
|
* Returns: the hash algorithm
|
||||||
|
*/
|
||||||
|
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_ivgen_free:
|
||||||
|
* @ivgen: the IV generator object
|
||||||
|
*
|
||||||
|
* Release all resources associated with @ivgen, or a no-op
|
||||||
|
* if @ivgen is NULL
|
||||||
|
*/
|
||||||
|
void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
|
||||||
|
|
||||||
|
#endif /* QCRYPTO_IVGEN_H__ */
|
152
include/crypto/pbkdf.h
Normal file
152
include/crypto/pbkdf.h
Normal file
|
@ -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__ */
|
44
include/crypto/random.h
Normal file
44
include/crypto/random.h
Normal file
|
@ -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__ */
|
86
include/crypto/xts.h
Normal file
86
include/crypto/xts.h
Normal file
|
@ -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-192: AES with 192 bit / 24 byte keys
|
||||||
# @aes-256: AES with 256 bit / 32 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.
|
# @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
|
# Since: 2.6
|
||||||
##
|
##
|
||||||
{ 'enum': 'QCryptoCipherAlgorithm',
|
{ 'enum': 'QCryptoCipherAlgorithm',
|
||||||
'prefix': 'QCRYPTO_CIPHER_ALG',
|
'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
|
# @ecb: Electronic Code Book
|
||||||
# @cbc: Cipher Block Chaining
|
# @cbc: Cipher Block Chaining
|
||||||
|
# @xts: XEX with tweaked code book and ciphertext stealing
|
||||||
# Since: 2.6
|
# Since: 2.6
|
||||||
##
|
##
|
||||||
{ 'enum': 'QCryptoCipherMode',
|
{ 'enum': 'QCryptoCipherMode',
|
||||||
'prefix': 'QCRYPTO_CIPHER_MODE',
|
'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' } }
|
||||||
|
|
5
tests/.gitignore
vendored
5
tests/.gitignore
vendored
|
@ -12,8 +12,12 @@ test-base64
|
||||||
test-bitops
|
test-bitops
|
||||||
test-blockjob-txn
|
test-blockjob-txn
|
||||||
test-coroutine
|
test-coroutine
|
||||||
|
test-crypto-afsplit
|
||||||
|
test-crypto-block
|
||||||
test-crypto-cipher
|
test-crypto-cipher
|
||||||
test-crypto-hash
|
test-crypto-hash
|
||||||
|
test-crypto-ivgen
|
||||||
|
test-crypto-pbkdf
|
||||||
test-crypto-secret
|
test-crypto-secret
|
||||||
test-crypto-tlscredsx509
|
test-crypto-tlscredsx509
|
||||||
test-crypto-tlscredsx509-work/
|
test-crypto-tlscredsx509-work/
|
||||||
|
@ -22,6 +26,7 @@ test-crypto-tlssession
|
||||||
test-crypto-tlssession-work/
|
test-crypto-tlssession-work/
|
||||||
test-crypto-tlssession-client/
|
test-crypto-tlssession-client/
|
||||||
test-crypto-tlssession-server/
|
test-crypto-tlssession-server/
|
||||||
|
test-crypto-xts
|
||||||
test-cutils
|
test-cutils
|
||||||
test-hbitmap
|
test-hbitmap
|
||||||
test-int128
|
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-command$(EXESUF)
|
||||||
check-unit-y += tests/test-io-channel-buffer$(EXESUF)
|
check-unit-y += tests/test-io-channel-buffer$(EXESUF)
|
||||||
check-unit-y += tests/test-base64$(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
|
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-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-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-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-cflags := $(TASN1_CFLAGS)
|
||||||
tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS)
|
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/io-channel-helpers.o $(test-io-obj-y)
|
||||||
tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \
|
tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \
|
||||||
tests/io-channel-helpers.o $(test-io-obj-y)
|
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/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
|
||||||
libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
|
libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
|
||||||
|
|
193
tests/test-crypto-afsplit.c
Normal file
193
tests/test-crypto-afsplit.c
Normal file
|
@ -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();
|
||||||
|
}
|
362
tests/test-crypto-block.c
Normal file
362
tests/test-crypto-block.c
Normal file
|
@ -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"
|
"ffd29f1bb5596ad94ea2d8e6196b7f09"
|
||||||
"30d8ed0bf2773af36dd82a6280c20926",
|
"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);
|
blocksize = qcrypto_cipher_get_block_len(data->alg);
|
||||||
ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode);
|
ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode);
|
||||||
|
|
||||||
|
if (data->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
|
g_assert_cmpint(keysize * 2, ==, nkey);
|
||||||
|
} else {
|
||||||
g_assert_cmpint(keysize, ==, nkey);
|
g_assert_cmpint(keysize, ==, nkey);
|
||||||
|
}
|
||||||
g_assert_cmpint(ivsize, ==, niv);
|
g_assert_cmpint(ivsize, ==, niv);
|
||||||
if (niv) {
|
if (niv) {
|
||||||
g_assert_cmpint(blocksize, ==, niv);
|
g_assert_cmpint(blocksize, ==, niv);
|
||||||
|
@ -380,8 +589,10 @@ int main(int argc, char **argv)
|
||||||
g_assert(qcrypto_init(NULL) == 0);
|
g_assert(qcrypto_init(NULL) == 0);
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||||
|
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_data_func(test_data[i].path, &test_data[i], test_cipher);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_test_add_func("/crypto/cipher/null-iv",
|
g_test_add_func("/crypto/cipher/null-iv",
|
||||||
test_cipher_null_iv);
|
test_cipher_null_iv);
|
||||||
|
|
173
tests/test-crypto-ivgen.c
Normal file
173
tests/test-crypto-ivgen.c
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* QEMU Crypto IV generator algorithms
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "crypto/ivgen.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct QCryptoIVGenTestData {
|
||||||
|
const char *path;
|
||||||
|
uint64_t sector;
|
||||||
|
QCryptoIVGenAlgorithm ivalg;
|
||||||
|
QCryptoHashAlgorithm hashalg;
|
||||||
|
QCryptoCipherAlgorithm cipheralg;
|
||||||
|
const uint8_t *key;
|
||||||
|
size_t nkey;
|
||||||
|
const uint8_t *iv;
|
||||||
|
size_t niv;
|
||||||
|
} test_data[] = {
|
||||||
|
/* Small */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain/1",
|
||||||
|
.sector = 0x1,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
|
||||||
|
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Big ! */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain/1f2e3d4c",
|
||||||
|
.sector = 0x1f2e3d4cULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
|
||||||
|
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Truncation */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain/1f2e3d4c5b6a7988",
|
||||||
|
.sector = 0x1f2e3d4c5b6a7988ULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
|
||||||
|
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Small */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain64/1",
|
||||||
|
.sector = 0x1,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||||
|
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Big ! */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain64/1f2e3d4c",
|
||||||
|
.sector = 0x1f2e3d4cULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||||
|
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* No Truncation */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/plain64/1f2e3d4c5b6a7988",
|
||||||
|
.sector = 0x1f2e3d4c5b6a7988ULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||||
|
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x4c\x3d\x2e\x1f"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Small */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/essiv/1",
|
||||||
|
.sector = 0x1,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
|
||||||
|
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
.hashalg = QCRYPTO_HASH_ALG_SHA256,
|
||||||
|
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||||
|
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
.nkey = 16,
|
||||||
|
.iv = (const uint8_t *)"\xd4\x83\x71\xb2\xa1\x94\x53\x88"
|
||||||
|
"\x1c\x7a\x2d\06\x2d\x0b\x65\x46",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* Big ! */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/essiv/1f2e3d4c",
|
||||||
|
.sector = 0x1f2e3d4cULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
|
||||||
|
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
.hashalg = QCRYPTO_HASH_ALG_SHA256,
|
||||||
|
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||||
|
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
.nkey = 16,
|
||||||
|
.iv = (const uint8_t *)"\x5d\x36\x09\x5d\xc6\x9e\x5e\xe9"
|
||||||
|
"\xe3\x02\x8d\xd8\x7a\x3d\xe7\x8f",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
/* No Truncation */
|
||||||
|
{
|
||||||
|
"/crypto/ivgen/essiv/1f2e3d4c5b6a7988",
|
||||||
|
.sector = 0x1f2e3d4c5b6a7988ULL,
|
||||||
|
.ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
|
||||||
|
.cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
|
||||||
|
.hashalg = QCRYPTO_HASH_ALG_SHA256,
|
||||||
|
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||||
|
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
.nkey = 16,
|
||||||
|
.iv = (const uint8_t *)"\x58\xbb\x81\x94\x51\x83\x23\x23"
|
||||||
|
"\x7a\x08\x93\xa9\xdc\xd2\xd9\xab",
|
||||||
|
.niv = 16,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void test_ivgen(const void *opaque)
|
||||||
|
{
|
||||||
|
const struct QCryptoIVGenTestData *data = opaque;
|
||||||
|
uint8_t *iv = g_new0(uint8_t, data->niv);
|
||||||
|
QCryptoIVGen *ivgen = qcrypto_ivgen_new(
|
||||||
|
data->ivalg,
|
||||||
|
data->cipheralg,
|
||||||
|
data->hashalg,
|
||||||
|
data->key,
|
||||||
|
data->nkey,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
qcrypto_ivgen_calculate(ivgen,
|
||||||
|
data->sector,
|
||||||
|
iv,
|
||||||
|
data->niv,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
g_assert(memcmp(iv, data->iv, data->niv) == 0);
|
||||||
|
|
||||||
|
qcrypto_ivgen_free(ivgen);
|
||||||
|
g_free(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||||
|
if (test_data[i].ivalg == QCRYPTO_IVGEN_ALG_ESSIV &&
|
||||||
|
!qcrypto_hash_supports(test_data[i].hashalg)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_test_add_data_func(test_data[i].path,
|
||||||
|
&(test_data[i]),
|
||||||
|
test_ivgen);
|
||||||
|
}
|
||||||
|
return g_test_run();
|
||||||
|
}
|
392
tests/test-crypto-pbkdf.c
Normal file
392
tests/test-crypto-pbkdf.c
Normal file
|
@ -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
|
423
tests/test-crypto-xts.c
Normal file
423
tests/test-crypto-xts.c
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue