mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+1
-1
@@ -1,6 +1,6 @@
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
stub-obj-y = stubs/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
||||
|
||||
|
||||
@@ -306,8 +306,10 @@ gtkabi=""
|
||||
gtk_gl="no"
|
||||
gnutls=""
|
||||
gnutls_hash=""
|
||||
gnutls_rnd=""
|
||||
nettle=""
|
||||
gcrypt=""
|
||||
gcrypt_kdf="no"
|
||||
vte=""
|
||||
virglrenderer=""
|
||||
tpm="yes"
|
||||
@@ -2201,6 +2203,13 @@ if test "$gnutls" != "no"; then
|
||||
gnutls_hash="no"
|
||||
fi
|
||||
|
||||
# gnutls_rnd requires >= 2.11.0
|
||||
if $pkg_config --exists "gnutls >= 2.11.0"; then
|
||||
gnutls_rnd="yes"
|
||||
else
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
if $pkg_config --exists 'gnutls >= 3.0'; then
|
||||
gnutls_gcrypt=no
|
||||
gnutls_nettle=yes
|
||||
@@ -2228,9 +2237,11 @@ if test "$gnutls" != "no"; then
|
||||
else
|
||||
gnutls="no"
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
else
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
|
||||
@@ -2292,6 +2303,19 @@ if test "$gcrypt" != "no"; then
|
||||
if test -z "$nettle"; then
|
||||
nettle="no"
|
||||
fi
|
||||
|
||||
cat > $TMPC << EOF
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_kdf_derive(NULL, 0, GCRY_KDF_PBKDF2,
|
||||
GCRY_MD_SHA256,
|
||||
NULL, 0, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||
gcrypt_kdf=yes
|
||||
fi
|
||||
else
|
||||
if test "$gcrypt" = "yes"; then
|
||||
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||
@@ -4714,7 +4738,9 @@ echo "GTK support $gtk"
|
||||
echo "GTK GL support $gtk_gl"
|
||||
echo "GNUTLS support $gnutls"
|
||||
echo "GNUTLS hash $gnutls_hash"
|
||||
echo "GNUTLS rnd $gnutls_rnd"
|
||||
echo "libgcrypt $gcrypt"
|
||||
echo "libgcrypt kdf $gcrypt_kdf"
|
||||
if test "$nettle" = "yes"; then
|
||||
echo "nettle $nettle ($nettle_version)"
|
||||
else
|
||||
@@ -5092,8 +5118,14 @@ fi
|
||||
if test "$gnutls_hash" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gnutls_rnd" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gcrypt" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
||||
if test "$gcrypt_kdf" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$nettle" = "yes" ; then
|
||||
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||||
|
||||
@@ -8,6 +8,23 @@ crypto-obj-y += tlscredsanon.o
|
||||
crypto-obj-y += tlscredsx509.o
|
||||
crypto-obj-y += tlssession.o
|
||||
crypto-obj-y += secret.o
|
||||
crypto-obj-$(CONFIG_GCRYPT) += random-gcrypt.o
|
||||
crypto-obj-$(if $(CONFIG_GCRYPT),n,$(CONFIG_GNUTLS_RND)) += random-gnutls.o
|
||||
crypto-obj-y += pbkdf.o
|
||||
crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o
|
||||
crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT_KDF)) += pbkdf-gcrypt.o
|
||||
crypto-obj-y += ivgen.o
|
||||
crypto-obj-y += ivgen-essiv.o
|
||||
crypto-obj-y += ivgen-plain.o
|
||||
crypto-obj-y += ivgen-plain64.o
|
||||
crypto-obj-y += afsplit.o
|
||||
crypto-obj-y += xts.o
|
||||
crypto-obj-y += block.o
|
||||
crypto-obj-y += block-qcow.o
|
||||
crypto-obj-y += block-luks.o
|
||||
|
||||
# Let the userspace emulators avoid linking gnutls/etc
|
||||
crypto-aes-obj-y = aes.o
|
||||
|
||||
stub-obj-y += random-stub.o
|
||||
stub-obj-y += pbkdf-stub.o
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* QEMU Crypto anti forensic information splitter
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* Derived from cryptsetup package lib/luks1/af.c
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/afsplit.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
|
||||
static void qcrypto_afsplit_xor(size_t blocklen,
|
||||
const uint8_t *in1,
|
||||
const uint8_t *in2,
|
||||
uint8_t *out)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < blocklen; i++) {
|
||||
out[i] = in1[i] ^ in2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint8_t *block,
|
||||
Error **errp)
|
||||
{
|
||||
size_t digestlen = qcrypto_hash_digest_len(hash);
|
||||
|
||||
size_t hashcount = blocklen / digestlen;
|
||||
size_t finallen = blocklen % digestlen;
|
||||
uint32_t i;
|
||||
|
||||
if (finallen) {
|
||||
hashcount++;
|
||||
} else {
|
||||
finallen = digestlen;
|
||||
}
|
||||
|
||||
for (i = 0; i < hashcount; i++) {
|
||||
uint8_t *out = NULL;
|
||||
size_t outlen = 0;
|
||||
uint32_t iv = cpu_to_be32(i);
|
||||
struct iovec in[] = {
|
||||
{ .iov_base = &iv,
|
||||
.iov_len = sizeof(iv) },
|
||||
{ .iov_base = block + (i * digestlen),
|
||||
.iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
|
||||
};
|
||||
|
||||
if (qcrypto_hash_bytesv(hash,
|
||||
in,
|
||||
G_N_ELEMENTS(in),
|
||||
&out, &outlen,
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(outlen == digestlen);
|
||||
memcpy(block + (i * digestlen), out,
|
||||
(i == (hashcount - 1)) ? finallen : digestlen);
|
||||
g_free(out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
out + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in,
|
||||
block,
|
||||
out + (i * blocklen));
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
out);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
||||
+1328
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption LUKS format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_LUKS_H__
|
||||
#define QCRYPTO_BLOCK_LUKS_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_luks;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_LUKS_H__ */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that the block encryption implemented in this file is broken
|
||||
* by design. This exists only to allow data to be liberated from
|
||||
* existing qcow[2] images and should not be used in any new areas.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/secret.h"
|
||||
|
||||
#define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
|
||||
|
||||
|
||||
static bool
|
||||
qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
|
||||
size_t buf_size G_GNUC_UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||
const char *keysecret,
|
||||
Error **errp)
|
||||
{
|
||||
char *password;
|
||||
int ret;
|
||||
uint8_t keybuf[16];
|
||||
int len;
|
||||
|
||||
memset(keybuf, 0, 16);
|
||||
|
||||
password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
|
||||
if (!password) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(password);
|
||||
memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
|
||||
g_free(password);
|
||||
|
||||
block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC);
|
||||
block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
0, 0, NULL, 0, errp);
|
||||
if (!block->ivgen) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC,
|
||||
keybuf, G_N_ELEMENTS(keybuf),
|
||||
errp);
|
||||
if (!block->cipher) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->payload_offset = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_open(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
|
||||
return 0;
|
||||
} else {
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp,
|
||||
"Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
return qcrypto_block_qcow_init(block,
|
||||
options->u.qcow.key_secret, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_create(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
|
||||
QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp, "Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
/* QCow2 has no special header, since everything is hardwired */
|
||||
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_block_qcow_cleanup(QCryptoBlock *block)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_decrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_encrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
const QCryptoBlockDriver qcrypto_block_driver_qcow = {
|
||||
.open = qcrypto_block_qcow_open,
|
||||
.create = qcrypto_block_qcow_create,
|
||||
.cleanup = qcrypto_block_qcow_cleanup,
|
||||
.decrypt = qcrypto_block_qcow_decrypt,
|
||||
.encrypt = qcrypto_block_qcow_encrypt,
|
||||
.has_format = qcrypto_block_qcow_has_format,
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_QCOW_H__
|
||||
#define QCRYPTO_BLOCK_QCOW_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_qcow;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_QCOW_H__ */
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/blockpriv.h"
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/block-luks.h"
|
||||
|
||||
static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
|
||||
[Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
|
||||
[Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
|
||||
};
|
||||
|
||||
|
||||
bool qcrypto_block_has_format(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
const QCryptoBlockDriver *driver;
|
||||
|
||||
if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[format]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
driver = qcrypto_block_drivers[format];
|
||||
|
||||
return driver->has_format(buf, len);
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->open(block, options,
|
||||
readfunc, opaque, flags, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->create(block, options, initfunc,
|
||||
writefunc, opaque, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->decrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->encrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
|
||||
{
|
||||
return block->cipher;
|
||||
}
|
||||
|
||||
|
||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
|
||||
{
|
||||
return block->ivgen;
|
||||
}
|
||||
|
||||
|
||||
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
|
||||
{
|
||||
return block->kdfhash;
|
||||
}
|
||||
|
||||
|
||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
|
||||
{
|
||||
return block->payload_offset;
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_block_free(QCryptoBlock *block)
|
||||
{
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->driver->cleanup(block);
|
||||
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
g_free(block);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
while (len > 0) {
|
||||
size_t nbytes;
|
||||
if (niv) {
|
||||
if (qcrypto_ivgen_calculate(ivgen,
|
||||
startsector,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_setiv(cipher,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = len > sectorsize ? sectorsize : len;
|
||||
if (qcrypto_cipher_decrypt(cipher, buf, buf,
|
||||
nbytes, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
startsector++;
|
||||
buf += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
g_free(iv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
while (len > 0) {
|
||||
size_t nbytes;
|
||||
if (niv) {
|
||||
if (qcrypto_ivgen_calculate(ivgen,
|
||||
startsector,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_setiv(cipher,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = len > sectorsize ? sectorsize : len;
|
||||
if (qcrypto_cipher_encrypt(cipher, buf, buf,
|
||||
nbytes, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
startsector++;
|
||||
buf += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
g_free(iv);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_PRIV_H__
|
||||
#define QCRYPTO_BLOCK_PRIV_H__
|
||||
|
||||
#include "crypto/block.h"
|
||||
|
||||
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
|
||||
|
||||
struct QCryptoBlock {
|
||||
QCryptoBlockFormat format;
|
||||
|
||||
const QCryptoBlockDriver *driver;
|
||||
void *opaque;
|
||||
|
||||
QCryptoCipher *cipher;
|
||||
QCryptoIVGen *ivgen;
|
||||
QCryptoHashAlgorithm kdfhash;
|
||||
size_t niv;
|
||||
uint64_t payload_offset; /* In bytes */
|
||||
};
|
||||
|
||||
struct QCryptoBlockDriver {
|
||||
int (*open)(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp);
|
||||
|
||||
int (*create)(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
void (*cleanup)(QCryptoBlock *block);
|
||||
|
||||
int (*encrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
int (*decrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
bool (*has_format)(const uint8_t *buf,
|
||||
size_t buflen);
|
||||
};
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_PRIV_H__ */
|
||||
+154
-53
@@ -21,11 +21,17 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/desrfb.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
|
||||
struct QCryptoCipherBuiltinAESContext {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||
struct QCryptoCipherBuiltinAES {
|
||||
AES_KEY encrypt_key;
|
||||
AES_KEY decrypt_key;
|
||||
QCryptoCipherBuiltinAESContext key;
|
||||
QCryptoCipherBuiltinAESContext key_tweak;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||
@@ -67,6 +73,82 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
@@ -75,29 +157,26 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.encrypt_key,
|
||||
&ctxt->state.aes.key.enc,
|
||||
ctxt->state.aes.iv, 1);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -112,29 +191,26 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.decrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.decrypt_key,
|
||||
&ctxt->state.aes.key.dec,
|
||||
ctxt->state.aes.iv, 0);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_decrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -166,21 +242,46 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
||||
QCryptoCipherBuiltin *ctxt;
|
||||
|
||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
|
||||
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ctxt->blocksize = AES_BLOCK_SIZE;
|
||||
@@ -322,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
cipher->alg = alg;
|
||||
cipher->mode = mode;
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
+145
-26
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
|
||||
@@ -29,6 +31,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -38,7 +46,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||
struct QCryptoCipherGcrypt {
|
||||
gcry_cipher_hd_t handle;
|
||||
gcry_cipher_hd_t tweakhandle;
|
||||
size_t blocksize;
|
||||
uint8_t *iv;
|
||||
};
|
||||
|
||||
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
@@ -53,6 +63,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
@@ -63,7 +74,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -84,6 +95,30 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcryalg = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
gcryalg = GCRY_CIPHER_CAST5;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
gcryalg = GCRY_CIPHER_SERPENT128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
gcryalg = GCRY_CIPHER_SERPENT192;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
gcryalg = GCRY_CIPHER_SERPENT256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
return NULL;
|
||||
@@ -101,6 +136,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot initialize cipher: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
/* We're using standard DES cipher from gcrypt, so we need
|
||||
@@ -112,13 +155,44 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
g_free(rfbkey);
|
||||
ctx->blocksize = 8;
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
ctx->blocksize = 16;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
nkey /= 2;
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
switch (cipher->alg) {
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->blocksize = 16;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->blocksize = 8;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
}
|
||||
|
||||
cipher->opaque = ctx;
|
||||
@@ -126,6 +200,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
error:
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
return NULL;
|
||||
@@ -140,11 +217,35 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||
}
|
||||
ctx = cipher->opaque;
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
@@ -160,13 +261,20 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -188,13 +296,20 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -213,12 +328,16 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
if (ctx->iv) {
|
||||
memcpy(ctx->iv, iv, niv);
|
||||
} else {
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+175
-20
@@ -19,10 +19,15 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <nettle/nettle-types.h>
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/des.h>
|
||||
#include <nettle/cbc.h>
|
||||
#include <nettle/cast128.h>
|
||||
#include <nettle/serpent.h>
|
||||
#include <nettle/twofish.h>
|
||||
|
||||
#if CONFIG_NETTLE_VERSION_MAJOR < 3
|
||||
typedef nettle_crypt_func nettle_cipher_func;
|
||||
@@ -39,16 +44,23 @@ static nettle_cipher_func aes_decrypt_wrapper;
|
||||
static nettle_cipher_func des_encrypt_wrapper;
|
||||
static nettle_cipher_func des_decrypt_wrapper;
|
||||
|
||||
typedef struct QCryptoNettleAES {
|
||||
struct aes_ctx enc;
|
||||
struct aes_ctx dec;
|
||||
} QCryptoNettleAES;
|
||||
|
||||
static void aes_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_encrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_encrypt(&aesctx->enc, length, dst, src);
|
||||
}
|
||||
|
||||
static void aes_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_decrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_decrypt(&aesctx->dec, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
@@ -63,12 +75,52 @@ static void des_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
|
||||
struct QCryptoCipherNettle {
|
||||
void *ctx_encrypt;
|
||||
void *ctx_decrypt;
|
||||
/* Primary cipher context for all modes */
|
||||
void *ctx;
|
||||
/* Second cipher context for XTS mode only */
|
||||
void *ctx_tweak;
|
||||
/* Cipher callbacks for both contexts */
|
||||
nettle_cipher_func *alg_encrypt;
|
||||
nettle_cipher_func *alg_decrypt;
|
||||
|
||||
uint8_t *iv;
|
||||
size_t blocksize;
|
||||
};
|
||||
@@ -80,6 +132,13 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -99,13 +158,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -117,10 +177,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
|
||||
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
|
||||
ctx->ctx = g_new0(struct des_ctx, 1);
|
||||
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||
des_set_key(ctx->ctx_encrypt, rfbkey);
|
||||
des_set_key(ctx->ctx, rfbkey);
|
||||
g_free(rfbkey);
|
||||
|
||||
ctx->alg_encrypt = des_encrypt_wrapper;
|
||||
@@ -132,17 +191,95 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
|
||||
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
nkey /= 2;
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->enc,
|
||||
nkey, key + nkey);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->dec,
|
||||
nkey, key + nkey);
|
||||
} else {
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = aes_encrypt_wrapper;
|
||||
ctx->alg_decrypt = aes_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = AES_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->ctx = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
cast5_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = cast128_encrypt_wrapper;
|
||||
ctx->alg_decrypt = cast128_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = CAST128_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
ctx->ctx = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
serpent_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = serpent_encrypt_wrapper;
|
||||
ctx->alg_decrypt = serpent_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = SERPENT_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->ctx = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
twofish_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt = twofish_encrypt_wrapper;
|
||||
ctx->alg_decrypt = twofish_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = TWOFISH_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
goto error;
|
||||
@@ -170,8 +307,8 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||
|
||||
ctx = cipher->opaque;
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx->ctx_encrypt);
|
||||
g_free(ctx->ctx_decrypt);
|
||||
g_free(ctx->ctx);
|
||||
g_free(ctx->ctx_tweak);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
@@ -193,14 +330,21 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
|
||||
ctx->alg_encrypt(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
|
||||
cbc_encrypt(ctx->ctx, ctx->alg_encrypt,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt, ctx->alg_encrypt,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
@@ -226,15 +370,26 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
len, out, in);
|
||||
ctx->alg_decrypt(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
ctx->alg_decrypt, ctx->blocksize, ctx->iv,
|
||||
cbc_decrypt(ctx->ctx, ctx->alg_decrypt,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp, "Block size must be %d not %zu",
|
||||
XTS_BLOCK_SIZE, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt, ctx->alg_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
|
||||
+37
-4
@@ -27,6 +27,13 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
|
||||
};
|
||||
|
||||
static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
@@ -34,11 +41,19 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
|
||||
};
|
||||
|
||||
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
||||
[QCRYPTO_CIPHER_MODE_CBC] = true,
|
||||
[QCRYPTO_CIPHER_MODE_XTS] = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -79,6 +94,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
|
||||
|
||||
static bool
|
||||
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -88,10 +104,27 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
error_setg(errp, "XTS mode not compatible with DES-RFB");
|
||||
return false;
|
||||
}
|
||||
if (nkey % 2) {
|
||||
error_setg(errp, "XTS cipher key length should be a multiple of 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != (nkey / 2)) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg] * 2);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - essiv
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-essiv.h"
|
||||
|
||||
typedef struct QCryptoIVGenESSIV QCryptoIVGenESSIV;
|
||||
struct QCryptoIVGenESSIV {
|
||||
QCryptoCipher *cipher;
|
||||
};
|
||||
|
||||
static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *salt;
|
||||
size_t nhash;
|
||||
size_t nsalt;
|
||||
QCryptoIVGenESSIV *essiv = g_new0(QCryptoIVGenESSIV, 1);
|
||||
|
||||
/* Not necessarily the same as nkey */
|
||||
nsalt = qcrypto_cipher_get_key_len(ivgen->cipher);
|
||||
|
||||
nhash = qcrypto_hash_digest_len(ivgen->hash);
|
||||
/* Salt must be larger of hash size or key size */
|
||||
salt = g_new0(uint8_t, MAX(nhash, nsalt));
|
||||
|
||||
if (qcrypto_hash_bytes(ivgen->hash, (const gchar *)key, nkey,
|
||||
&salt, &nhash,
|
||||
errp) < 0) {
|
||||
g_free(essiv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now potentially truncate salt to match cipher key len */
|
||||
essiv->cipher = qcrypto_cipher_new(ivgen->cipher,
|
||||
QCRYPTO_CIPHER_MODE_ECB,
|
||||
salt, MIN(nhash, nsalt),
|
||||
errp);
|
||||
if (!essiv->cipher) {
|
||||
g_free(essiv);
|
||||
g_free(salt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_free(salt);
|
||||
ivgen->private = essiv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_essiv_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||
size_t ndata = qcrypto_cipher_get_block_len(ivgen->cipher);
|
||||
uint8_t *data = g_new(uint8_t, ndata);
|
||||
|
||||
sector = cpu_to_le64(sector);
|
||||
memcpy(data, (uint8_t *)§or, ndata);
|
||||
if (sizeof(sector) < ndata) {
|
||||
memset(data + sizeof(sector), 0, ndata - sizeof(sector));
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_encrypt(essiv->cipher,
|
||||
data,
|
||||
data,
|
||||
ndata,
|
||||
errp) < 0) {
|
||||
g_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ndata > niv) {
|
||||
ndata = niv;
|
||||
}
|
||||
memcpy(iv, data, ndata);
|
||||
if (ndata < niv) {
|
||||
memset(iv + ndata, 0, niv - ndata);
|
||||
}
|
||||
g_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_essiv_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||
|
||||
qcrypto_cipher_free(essiv->cipher);
|
||||
g_free(essiv);
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_essiv = {
|
||||
.init = qcrypto_ivgen_essiv_init,
|
||||
.calculate = qcrypto_ivgen_essiv_calculate,
|
||||
.cleanup = qcrypto_ivgen_essiv_cleanup,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - essiv
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_ESSIV_H__
|
||||
#define QCRYPTO_IVGEN_ESSIV_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_essiv;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_ESSIV_H__ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-plain.h"
|
||||
|
||||
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
size_t ivprefix;
|
||||
uint32_t shortsector = cpu_to_le32((sector & 0xffffffff));
|
||||
ivprefix = sizeof(shortsector);
|
||||
if (ivprefix > niv) {
|
||||
ivprefix = niv;
|
||||
}
|
||||
memcpy(iv, &shortsector, ivprefix);
|
||||
if (ivprefix < niv) {
|
||||
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_plain = {
|
||||
.init = qcrypto_ivgen_plain_init,
|
||||
.calculate = qcrypto_ivgen_plain_calculate,
|
||||
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_PLAIN_H__
|
||||
#define QCRYPTO_IVGEN_PLAIN_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_PLAIN_H__ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-plain.h"
|
||||
|
||||
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
size_t ivprefix;
|
||||
ivprefix = sizeof(sector);
|
||||
sector = cpu_to_le64(sector);
|
||||
if (ivprefix > niv) {
|
||||
ivprefix = niv;
|
||||
}
|
||||
memcpy(iv, §or, ivprefix);
|
||||
if (ivprefix < niv) {
|
||||
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_plain64 = {
|
||||
.init = qcrypto_ivgen_plain_init,
|
||||
.calculate = qcrypto_ivgen_plain_calculate,
|
||||
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain64
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_PLAIN64_H__
|
||||
#define QCRYPTO_IVGEN_PLAIN64_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain64;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_PLAIN64_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user