From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Subject: [Qemu-devel] [PATCH v1 03/15] crypto: add support for generating initialization vectors
Date: Tue, 12 Jan 2016 18:56:10 +0000 [thread overview]
Message-ID: <1452624982-19332-4-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1452624982-19332-1-git-send-email-berrange@redhat.com>
There are a number of different algorithms that can be used
to generate initialization vectors for disk encryption. This
introduces a simple internal QCryptoBlockIV object to provide
a consistent internal API to the different algorithms. The
initially implemented algorithms are 'plain', 'plain64' and
'essiv', each matching the same named algorithm provided
by the Linux kernel dm-crypt driver.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
crypto/Makefile.objs | 4 ++
crypto/ivgen-essiv.c | 116 ++++++++++++++++++++++++++++++++
crypto/ivgen-essiv.h | 28 ++++++++
crypto/ivgen-plain.c | 60 +++++++++++++++++
crypto/ivgen-plain.h | 28 ++++++++
crypto/ivgen-plain64.c | 60 +++++++++++++++++
crypto/ivgen-plain64.h | 28 ++++++++
crypto/ivgen.c | 117 ++++++++++++++++++++++++++++++++
crypto/ivgenpriv.h | 47 +++++++++++++
include/crypto/ivgen.h | 167 +++++++++++++++++++++++++++++++++++++++++++++
qapi/crypto.json | 16 +++++
tests/.gitignore | 1 +
tests/Makefile | 2 +
tests/test-crypto-ivgen.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++
14 files changed, 842 insertions(+)
create mode 100644 crypto/ivgen-essiv.c
create mode 100644 crypto/ivgen-essiv.h
create mode 100644 crypto/ivgen-plain.c
create mode 100644 crypto/ivgen-plain.h
create mode 100644 crypto/ivgen-plain64.c
create mode 100644 crypto/ivgen-plain64.h
create mode 100644 crypto/ivgen.c
create mode 100644 crypto/ivgenpriv.h
create mode 100644 include/crypto/ivgen.h
create mode 100644 tests/test-crypto-ivgen.c
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index c1cf45c..a973483 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -10,6 +10,10 @@ crypto-obj-y += tlssession.o
crypto-obj-y += secret.o
crypto-obj-y += random.o
crypto-obj-y += pbkdf.o
+crypto-obj-y += ivgen.o
+crypto-obj-y += ivgen-essiv.o
+crypto-obj-y += ivgen-plain.o
+crypto-obj-y += ivgen-plain64.o
# Let the userspace emulators avoid linking gnutls/etc
crypto-aes-obj-y = aes.o
diff --git a/crypto/ivgen-essiv.c b/crypto/ivgen-essiv.c
new file mode 100644
index 0000000..fad8f95
--- /dev/null
+++ b/crypto/ivgen-essiv.c
@@ -0,0 +1,116 @@
+/*
+ * QEMU Crypto block IV generator - essiv
+ *
+ * Copyright (c) 2015 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/ivgen-essiv.h"
+
+typedef struct QCryptoIVGenESSIV QCryptoIVGenESSIV;
+struct QCryptoIVGenESSIV {
+ QCryptoCipher *cipher;
+ QCryptoCipherAlgorithm cipheralg;
+};
+
+static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
+ QCryptoCipherAlgorithm cipheralg,
+ QCryptoHashAlgorithm hash,
+ const uint8_t *key, size_t nkey,
+ Error **errp)
+{
+ uint8_t *salt;
+ size_t nhash;
+ QCryptoIVGenESSIV *essiv = g_new0(QCryptoIVGenESSIV, 1);
+
+ nhash = qcrypto_hash_digest_len(hash);
+ /* Salt must be larger of hash size or key size */
+ salt = g_new0(uint8_t, nhash > nkey ? nhash : nkey);
+
+ if (qcrypto_hash_bytes(hash, (const gchar*)key, nkey,
+ &salt, &nhash,
+ errp) < 0) {
+ g_free(essiv);
+ return -1;
+ }
+
+ essiv->cipheralg = cipheralg;
+ essiv->cipher = qcrypto_cipher_new(cipheralg,
+ QCRYPTO_CIPHER_MODE_ECB,
+ salt, nkey,
+ 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(essiv->cipheralg);
+ uint8_t *data = g_new(uint8_t, ndata);
+
+ sector = cpu_to_le64((uint32_t)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 = {
+ qcrypto_ivgen_essiv_init,
+ qcrypto_ivgen_essiv_calculate,
+ qcrypto_ivgen_essiv_cleanup,
+};
+
diff --git a/crypto/ivgen-essiv.h b/crypto/ivgen-essiv.h
new file mode 100644
index 0000000..eed80c1
--- /dev/null
+++ b/crypto/ivgen-essiv.h
@@ -0,0 +1,28 @@
+/*
+ * QEMU Crypto block IV generator - essiv
+ *
+ * Copyright (c) 2015 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__ */
diff --git a/crypto/ivgen-plain.c b/crypto/ivgen-plain.c
new file mode 100644
index 0000000..784ebc1
--- /dev/null
+++ b/crypto/ivgen-plain.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Crypto block IV generator - plain
+ *
+ * Copyright (c) 2015 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/ivgen-plain.h"
+
+static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
+ QCryptoCipherAlgorithm cipheralg,
+ QCryptoHashAlgorithm hash,
+ 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((uint32_t)(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 = {
+ qcrypto_ivgen_plain_init,
+ qcrypto_ivgen_plain_calculate,
+ qcrypto_ivgen_plain_cleanup,
+};
+
diff --git a/crypto/ivgen-plain.h b/crypto/ivgen-plain.h
new file mode 100644
index 0000000..82c0939
--- /dev/null
+++ b/crypto/ivgen-plain.h
@@ -0,0 +1,28 @@
+/*
+ * QEMU Crypto block IV generator - plain
+ *
+ * Copyright (c) 2015 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__ */
diff --git a/crypto/ivgen-plain64.c b/crypto/ivgen-plain64.c
new file mode 100644
index 0000000..40bbcc2
--- /dev/null
+++ b/crypto/ivgen-plain64.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Crypto block IV generator - plain
+ *
+ * Copyright (c) 2015 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/ivgen-plain.h"
+
+static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
+ QCryptoCipherAlgorithm cipheralg,
+ QCryptoHashAlgorithm hash,
+ 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 = {
+ qcrypto_ivgen_plain_init,
+ qcrypto_ivgen_plain_calculate,
+ qcrypto_ivgen_plain_cleanup,
+};
+
diff --git a/crypto/ivgen-plain64.h b/crypto/ivgen-plain64.h
new file mode 100644
index 0000000..031d8f4
--- /dev/null
+++ b/crypto/ivgen-plain64.h
@@ -0,0 +1,28 @@
+/*
+ * QEMU Crypto block IV generator - plain64
+ *
+ * Copyright (c) 2015 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__ */
diff --git a/crypto/ivgen.c b/crypto/ivgen.c
new file mode 100644
index 0000000..2353660
--- /dev/null
+++ b/crypto/ivgen.c
@@ -0,0 +1,117 @@
+/*
+ * QEMU Crypto block IV generator
+ *
+ * Copyright (c) 2015 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"
+#include "crypto/ivgen-plain.h"
+#include "crypto/ivgen-plain64.h"
+#include "crypto/ivgen-essiv.h"
+
+
+/**
+ * @qcrypto_ivgen_new:
+ * @alg: the initialization vector generator algorithm
+ * @cipheralg: the cipher algorithm (if applicable)
+ * @hash: the hash algorithm (if applicable)
+ * @key: the encryption key (if applicable)
+ * @nkey: the length of @key in bytes
+ * @errp: pointer to an uninitialized error object
+ *
+ * Create a new initialization vector generator implementing
+ * the algorithm specified in @alg.
+ *
+ * For the ESSIV algorithm, the @cipheralg, @ciphermode
+ * @hash, @key and @nkey parameters are required. For
+ * other algorithms they should be NULL / zero as
+ * appropriate.
+ *
+ * Returns the 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)
+{
+ QCryptoIVGen *ivgen = g_new0(QCryptoIVGen, 1);
+
+
+ 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, cipheralg, hash, key, nkey, errp) < 0) {
+ g_free(ivgen);
+ return NULL;
+ }
+
+ return ivgen;
+}
+
+
+/**
+ * qcrypto_ivgen_calculate:
+ * @ivgen: the IV generator object
+ * @sector: the sector number in the volume
+ * @iv: buffer to store the generated IV in
+ * @niv: length of @iv in bytes
+ * @errp: pointer to an uninitialized error object
+ *
+ * Calculate a new initialization vector storing the
+ * result in @iv. The @iv buffer must be pre-allocated
+ * by the caller and @niv provides its length in bytes.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+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);
+}
+
+
+/**
+ * qcrypto_ivgen_free:
+ * @ivgen: the IV generator object
+ *
+ * Release all resources associated with the
+ * IV generator
+ */
+void qcrypto_ivgen_free(QCryptoIVGen *ivgen)
+{
+ if (!ivgen) {
+ return;
+ }
+ ivgen->driver->cleanup(ivgen);
+ g_free(ivgen);
+}
diff --git a/crypto/ivgenpriv.h b/crypto/ivgenpriv.h
new file mode 100644
index 0000000..f9ebe8a
--- /dev/null
+++ b/crypto/ivgenpriv.h
@@ -0,0 +1,47 @@
+/*
+ * QEMU Crypto block IV generator
+ *
+ * Copyright (c) 2015 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 *biv,
+ QCryptoCipherAlgorithm cipheralg,
+ QCryptoHashAlgorithm hash,
+ const uint8_t *key, size_t nkey,
+ Error **errp);
+ int (*calculate)(QCryptoIVGen *biv,
+ uint64_t sector,
+ uint8_t *iv, size_t niv,
+ Error **errp);
+ void (*cleanup)(QCryptoIVGen *biv);
+};
+
+struct QCryptoIVGen {
+ QCryptoIVGenDriver *driver;
+ void *private;
+};
+
+
+#endif /* QCRYPTO_IVGEN_PRIV_H__ */
diff --git a/include/crypto/ivgen.h b/include/crypto/ivgen.h
new file mode 100644
index 0000000..6f8acdd
--- /dev/null
+++ b/include/crypto/ivgen.h
@@ -0,0 +1,167 @@
+/*
+ * QEMU Crypto block IV generator
+ *
+ * Copyright (c) 2015 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;
+ * }
+ * }
+ *
+ * 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 an uninitialized 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_free:
+ * @ivgen: the IV generator object
+ *
+ * Release all resources associated with @ivgen
+ */
+void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
+
+#endif /* QCRYPTO_IVGEN_H__ */
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 4bd690f..48946b0 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -78,3 +78,19 @@
{ 'enum': 'QCryptoCipherMode',
'prefix': 'QCRYPTO_CIPHER_MODE',
'data': ['ecb', 'cbc']}
+
+
+##
+# QCryptoIVGenAlgorithm:
+#
+# The supported algorithms for generating initialization
+# vectors for full disk encryption
+#
+# @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']}
diff --git a/tests/.gitignore b/tests/.gitignore
index db6b9be..369f848 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -14,6 +14,7 @@ test-blockjob-txn
test-coroutine
test-crypto-cipher
test-crypto-hash
+test-crypto-ivgen
test-crypto-pbkdf
test-crypto-secret
test-crypto-tlscredsx509
diff --git a/tests/Makefile b/tests/Makefile
index 833a290..5fdbaf0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -93,6 +93,7 @@ check-unit-y += tests/test-io-channel-command$(EXESUF)
check-unit-y += tests/test-io-channel-buffer$(EXESUF)
check-unit-y += tests/test-base64$(EXESUF)
check-unit-y += tests/test-crypto-pbkdf$(EXESUF)
+check-unit-y += tests/test-crypto-ivgen$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -497,6 +498,7 @@ tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \
tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \
tests/io-channel-helpers.o $(test-io-obj-y)
tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y)
+tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y)
libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
diff --git a/tests/test-crypto-ivgen.c b/tests/test-crypto-ivgen.c
new file mode 100644
index 0000000..3c58e46
--- /dev/null
+++ b/tests/test-crypto-ivgen.c
@@ -0,0 +1,168 @@
+/*
+ * QEMU Crypto IV generator algorithms
+ *
+ * Copyright (c) 2015 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/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 *)"\xe8\x6d\xb9\x11\x17\x7a\x86\xed"
+ "\x7e\xe6\xb2\xe7\xbf\x8f\xa1\x8c",
+ .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++) {
+ g_test_add_data_func(test_data[i].path,
+ &(test_data[i]),
+ test_ivgen);
+ }
+ return g_test_run();
+}
--
2.5.0
next prev parent reply other threads:[~2016-01-12 18:56 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-12 18:56 [Qemu-devel] [PATCH v1 00/15] Support LUKS encryption in block devices Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 01/15] crypto: add cryptographic random byte source Daniel P. Berrange
2016-01-13 2:46 ` Fam Zheng
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 02/15] crypto: add support for PBKDF2 algorithm Daniel P. Berrange
2016-01-13 5:53 ` Fam Zheng
2016-01-14 12:17 ` Daniel P. Berrange
2016-01-12 18:56 ` Daniel P. Berrange [this message]
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 04/15] crypto: add support for anti-forensic split algorithm Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 05/15] crypto: add block encryption framework Daniel P. Berrange
2016-01-13 23:40 ` Eric Blake
2016-01-14 12:16 ` Daniel P. Berrange
2016-01-18 19:48 ` Eric Blake
2016-01-19 9:41 ` Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 06/15] crypto: implement the LUKS block encryption format Daniel P. Berrange
2016-01-13 23:43 ` Eric Blake
2016-01-14 10:14 ` Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 07/15] block: add flag to indicate that no I/O will be performed Daniel P. Berrange
2016-01-13 17:44 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-01-13 17:56 ` Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 08/15] block: add generic full disk encryption driver Daniel P. Berrange
2016-01-13 23:47 ` Eric Blake
2016-01-14 10:15 ` Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 09/15] qcow2: make qcow2_encrypt_sectors encrypt in place Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 10/15] qcow2: convert QCow2 to use QCryptoBlock for encryption Daniel P. Berrange
2016-01-13 18:42 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-01-14 12:14 ` Daniel P. Berrange
2016-01-14 12:58 ` Kevin Wolf
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 11/15] qcow: make encrypt_sectors encrypt in place Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 12/15] qcow: convert QCow to use QCryptoBlock for encryption Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 13/15] block: rip out all traces of password prompting Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 14/15] block: remove all encryption handling APIs Daniel P. Berrange
2016-01-12 18:56 ` [Qemu-devel] [PATCH v1 15/15] block: remove support for legecy AES qcow/qcow2 encryption Daniel P. Berrange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1452624982-19332-4-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.