From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37011) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aRTIa-0004rP-BI for qemu-devel@nongnu.org; Thu, 04 Feb 2016 18:26:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aRTIZ-00015M-06 for qemu-devel@nongnu.org; Thu, 04 Feb 2016 18:26:52 -0500 References: <1453311539-1193-1-git-send-email-berrange@redhat.com> <1453311539-1193-6-git-send-email-berrange@redhat.com> From: Eric Blake Message-ID: <56B3DE32.4050901@redhat.com> Date: Thu, 4 Feb 2016 16:26:42 -0700 MIME-Version: 1.0 In-Reply-To: <1453311539-1193-6-git-send-email-berrange@redhat.com> Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="U1xNrL6i0wfD0fT9NFtrLiaxsiRBqS3IN" Subject: Re: [Qemu-devel] [PATCH v2 05/17] crypto: add support for anti-forensic split algorithm List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "Daniel P. Berrange" , qemu-devel@nongnu.org Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --U1xNrL6i0wfD0fT9NFtrLiaxsiRBqS3IN Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 01/20/2016 10:38 AM, Daniel P. Berrange wrote: > The LUKS format specifies an anti-forensic split algorithm which > is used to artificially expand the size of the key material on > disk. This is an implementation of that algorithm. >=20 > Signed-off-by: Daniel P. Berrange > --- > crypto/Makefile.objs | 1 + > crypto/afsplit.c | 162 ++++++++++++++++++++++++++++++++++++= ++++ > include/crypto/afsplit.h | 135 +++++++++++++++++++++++++++++++++ > tests/.gitignore | 1 + > tests/Makefile | 2 + > tests/test-crypto-afsplit.c | 176 ++++++++++++++++++++++++++++++++++++= ++++++++ > 6 files changed, 477 insertions(+) > create mode 100644 crypto/afsplit.c > create mode 100644 include/crypto/afsplit.h > create mode 100644 tests/test-crypto-afsplit.c >=20 In addition to Fam's findings, > +++ b/crypto/afsplit.c > @@ -0,0 +1,162 @@ > +/* > + * QEMU Crypto anti forensic information splitter > + * > + * Copyright (c) 2015-2016 Red Hat, Inc. > + * > + * Derived from cryptsetup package lib/lusk1/af.c > + * > + * Copyright (C) 2004, Clemens Fruhwirth > + * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved. > + * > + > +static void qcrypto_afsplit_xor(size_t blocklen, > + const uint8_t *in1, > + const uint8_t *in2, > + uint8_t *out) > +{ > + size_t i; > + for (i =3D 0; i < blocklen; i++) { > + out[i] =3D in1[i] ^ in2[i]; > + } Could be made faster using larger data types, if we know that things are properly aligned. I'm not sure if the compiler can automatically optimize this. I'm also not sure if this is ever on a hot path where it matters. > +} > + > + > +static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash, > + size_t blocklen, > + uint8_t *block, > + Error **errp) > +{ > + size_t digestlen =3D qcrypto_hash_digest_len(hash); > + > + size_t hashcount =3D blocklen / digestlen; > + size_t finallen =3D blocklen % digestlen; > + uint32_t i; > + > + if (finallen) { > + hashcount++; > + } else { > + finallen =3D blocklen; > + } > + > + for (i =3D 0; i < hashcount; i++) { > + uint8_t *out =3D NULL; > + size_t outlen =3D 0; > + uint32_t iv =3D cpu_to_be32(i); > + struct iovec in[] =3D { > + { .iov_base =3D &iv, > + .iov_len =3D sizeof(iv) }, > + { .iov_base =3D block + (i * digestlen), > + .iov_len =3D (i =3D=3D (hashcount - 1)) ? finallen : dig= estlen }, > + }; > + > + if (qcrypto_hash_bytesv(hash, > + in, > + G_N_ELEMENTS(in), > + &out, &outlen, > + errp) < 0) { > + return -1; > + } > + > + if (outlen !=3D digestlen) { > + error_setg(errp, "Hash output %zu not %zu", > + outlen, digestlen); > + g_free(out); Is this error even possible, or can it be an assert? > + return -1; > + } > + memcpy(block + (i * digestlen), out, > + (i =3D=3D (hashcount - 1)) ? finallen : digestlen); > + g_free(out); > + } > + > + return 0; > +} > + > + >=20 > +int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash, > + size_t blocklen, > + uint32_t stripes, > + const uint8_t *in, > + uint8_t *out, > + Error **errp) > +{ > + uint8_t *block =3D g_new0(uint8_t, blocklen); > + size_t i; >=20 > + > + qcrypto_afsplit_xor(blocklen, > + out + (i * blocklen), > + block, > + block); Should we ensure no overflow in the multiplication here (or rather, that the input blocklen * stripes is reasonable on input)? > +++ b/include/crypto/afsplit.h > + > +/** > + * This module implements the anti-forensic splitter that is specified= > + * as part of the LUKS format: > + * > + * http://clemens.endorphin.org/cryptography > + * http://clemens.endorphin.org/TKS1-draft.pdf > + * > + * The core idea is to take a short piece of data (key material) > + * and process it to expand it to a much larger piece of data. > + * The expansion process is reversable, to obtain the original s/reversable/reversible/ > + * short data. The key property of the expansion is that if any > + * byte in the larger data set is changed / missing, it should be > + * impossible to recreate the original short data. > + * > + > +/** > + * qcrypto_afsplit_encode: > + * @hash: the hash algorithm to use for data expansion > + * @blocklen: the size of @in in bytes > + * @stripes: the number of times to expand @in in size > + * @in: the master key to be expanded in size > + * @out: preallocted buffer to hold the split key s/preallocted/preallocated/ > + * @errp: pointer to a NULL-initialized error object > + * > + * Split the data in @in, which is @blocklen bytes in > + * size, to form a larger piece of data @out, which is > + * @blocklen * @stripes bytes in size. > + * > + * Returns: 0 on success, -1 on error; > + */ > +int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash, > + size_t blocklen, > + uint32_t stripes, > + const uint8_t *in, > + uint8_t *out, > + Error **errp); > + > +/** > + * qcrypto_afsplit_decode: > + * @hash: the hash algorithm to use for data compression > + * @blocklen: the size of @out in bytes > + * @stripes: the number of times to decrease @in in size > + * @in: the master key to be expanded in size > + * @out: preallocted buffer to hold the split key and again > + * @errp: pointer to a NULL-initialized error object > + * > + * Join the data in @in, which is @blocklen * @stripes > + * bytes in size, to form the original small piece o > + * data @out, which is @blocklen bytes in size. > + * > + * Returns: 0 on success, -1 on error; > + */ > +int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash, > + size_t blocklen, > + uint32_t stripes, > + const uint8_t *in, > + uint8_t *out, > + Error **errp); Markus may have an opinion on whether these functions could return void and just use the errp pointer to report errors; but I'm fine with how you've done it. --=20 Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org --U1xNrL6i0wfD0fT9NFtrLiaxsiRBqS3IN Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 Comment: Public key at http://people.redhat.com/eblake/eblake.gpg Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBCAAGBQJWs94zAAoJEKeha0olJ0Nqr9IH/AtSRWBfMno4xv1BC0k1CJGf lRfEMNHVSRhnsRteWthUbWq1xKkKdiLz/4r7Ei0lvROypwx6LhoIGSKZdszN3j99 BNCinnBVUlOLeV0g+cXPlkFEBxSDpBwWPz9ApOuhuqjKPWjNqUwBQHeeKOvl3wBO OPiFJlrX0UdkyHBrvOrPcGhJlDkPhz0vaGZlgihbI4b7JlrbnZHUjyxNlufPiL5/ RAiNLieiNxG9RRhVuvIwVlFtbOajT18p25dPrmvd425wTR/mZ5zrcxqnLWmiLNAr s6BqQY5lFVL6DfFJLp8Keye9Fq7TThEawXqpLCjPtppiulmp4FMqMdL9Z8AxbrA= =5DnH -----END PGP SIGNATURE----- --U1xNrL6i0wfD0fT9NFtrLiaxsiRBqS3IN--