15a95e0fcSDaniel P. Berrange /*
25a95e0fcSDaniel P. Berrange * QEMU Crypto anti forensic information splitter
35a95e0fcSDaniel P. Berrange *
45a95e0fcSDaniel P. Berrange * Copyright (c) 2015-2016 Red Hat, Inc.
55a95e0fcSDaniel P. Berrange *
65a95e0fcSDaniel P. Berrange * Derived from cryptsetup package lib/luks1/af.c
75a95e0fcSDaniel P. Berrange *
85a95e0fcSDaniel P. Berrange * Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
95a95e0fcSDaniel P. Berrange * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
105a95e0fcSDaniel P. Berrange *
11e361a772SThomas Huth * This program is free software; you can redistribute it and/or
125a95e0fcSDaniel P. Berrange * modify it under the terms of the GNU General Public License
135a95e0fcSDaniel P. Berrange * as published by the Free Software Foundation; either version 2
145a95e0fcSDaniel P. Berrange * of the License, or (at your option) any later version.
155a95e0fcSDaniel P. Berrange *
16e361a772SThomas Huth * This program is distributed in the hope that it will be useful,
175a95e0fcSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
185a95e0fcSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19e361a772SThomas Huth * General Public License for more details.
205a95e0fcSDaniel P. Berrange *
21e361a772SThomas Huth * You should have received a copy of the GNU General Public License
22e361a772SThomas Huth * along with this program; if not, see <http://www.gnu.org/licenses/>.
235a95e0fcSDaniel P. Berrange */
245a95e0fcSDaniel P. Berrange
255a95e0fcSDaniel P. Berrange #include "qemu/osdep.h"
2658369e22SPaolo Bonzini #include "qemu/bswap.h"
275a95e0fcSDaniel P. Berrange #include "crypto/afsplit.h"
285a95e0fcSDaniel P. Berrange #include "crypto/random.h"
295a95e0fcSDaniel P. Berrange
305a95e0fcSDaniel P. Berrange
qcrypto_afsplit_xor(size_t blocklen,const uint8_t * in1,const uint8_t * in2,uint8_t * out)315a95e0fcSDaniel P. Berrange static void qcrypto_afsplit_xor(size_t blocklen,
325a95e0fcSDaniel P. Berrange const uint8_t *in1,
335a95e0fcSDaniel P. Berrange const uint8_t *in2,
345a95e0fcSDaniel P. Berrange uint8_t *out)
355a95e0fcSDaniel P. Berrange {
365a95e0fcSDaniel P. Berrange size_t i;
375a95e0fcSDaniel P. Berrange for (i = 0; i < blocklen; i++) {
385a95e0fcSDaniel P. Berrange out[i] = in1[i] ^ in2[i];
395a95e0fcSDaniel P. Berrange }
405a95e0fcSDaniel P. Berrange }
415a95e0fcSDaniel P. Berrange
425a95e0fcSDaniel P. Berrange
qcrypto_afsplit_hash(QCryptoHashAlgo hash,size_t blocklen,uint8_t * block,Error ** errp)43*ef834aa2SMarkus Armbruster static int qcrypto_afsplit_hash(QCryptoHashAlgo hash,
445a95e0fcSDaniel P. Berrange size_t blocklen,
455a95e0fcSDaniel P. Berrange uint8_t *block,
465a95e0fcSDaniel P. Berrange Error **errp)
475a95e0fcSDaniel P. Berrange {
485a95e0fcSDaniel P. Berrange size_t digestlen = qcrypto_hash_digest_len(hash);
495a95e0fcSDaniel P. Berrange
505a95e0fcSDaniel P. Berrange size_t hashcount = blocklen / digestlen;
515a95e0fcSDaniel P. Berrange size_t finallen = blocklen % digestlen;
525a95e0fcSDaniel P. Berrange uint32_t i;
535a95e0fcSDaniel P. Berrange
545a95e0fcSDaniel P. Berrange if (finallen) {
555a95e0fcSDaniel P. Berrange hashcount++;
565a95e0fcSDaniel P. Berrange } else {
575a95e0fcSDaniel P. Berrange finallen = digestlen;
585a95e0fcSDaniel P. Berrange }
595a95e0fcSDaniel P. Berrange
605a95e0fcSDaniel P. Berrange for (i = 0; i < hashcount; i++) {
6157b9f113SDaniel P. Berrangé g_autofree uint8_t *out = NULL;
625a95e0fcSDaniel P. Berrange size_t outlen = 0;
635a95e0fcSDaniel P. Berrange uint32_t iv = cpu_to_be32(i);
645a95e0fcSDaniel P. Berrange struct iovec in[] = {
655a95e0fcSDaniel P. Berrange { .iov_base = &iv,
665a95e0fcSDaniel P. Berrange .iov_len = sizeof(iv) },
675a95e0fcSDaniel P. Berrange { .iov_base = block + (i * digestlen),
685a95e0fcSDaniel P. Berrange .iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
695a95e0fcSDaniel P. Berrange };
705a95e0fcSDaniel P. Berrange
715a95e0fcSDaniel P. Berrange if (qcrypto_hash_bytesv(hash,
725a95e0fcSDaniel P. Berrange in,
735a95e0fcSDaniel P. Berrange G_N_ELEMENTS(in),
745a95e0fcSDaniel P. Berrange &out, &outlen,
755a95e0fcSDaniel P. Berrange errp) < 0) {
765a95e0fcSDaniel P. Berrange return -1;
775a95e0fcSDaniel P. Berrange }
785a95e0fcSDaniel P. Berrange
795a95e0fcSDaniel P. Berrange assert(outlen == digestlen);
805a95e0fcSDaniel P. Berrange memcpy(block + (i * digestlen), out,
815a95e0fcSDaniel P. Berrange (i == (hashcount - 1)) ? finallen : digestlen);
825a95e0fcSDaniel P. Berrange }
835a95e0fcSDaniel P. Berrange
845a95e0fcSDaniel P. Berrange return 0;
855a95e0fcSDaniel P. Berrange }
865a95e0fcSDaniel P. Berrange
875a95e0fcSDaniel P. Berrange
qcrypto_afsplit_encode(QCryptoHashAlgo hash,size_t blocklen,uint32_t stripes,const uint8_t * in,uint8_t * out,Error ** errp)88*ef834aa2SMarkus Armbruster int qcrypto_afsplit_encode(QCryptoHashAlgo hash,
895a95e0fcSDaniel P. Berrange size_t blocklen,
905a95e0fcSDaniel P. Berrange uint32_t stripes,
915a95e0fcSDaniel P. Berrange const uint8_t *in,
925a95e0fcSDaniel P. Berrange uint8_t *out,
935a95e0fcSDaniel P. Berrange Error **errp)
945a95e0fcSDaniel P. Berrange {
9557b9f113SDaniel P. Berrangé g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
965a95e0fcSDaniel P. Berrange size_t i;
975a95e0fcSDaniel P. Berrange
985a95e0fcSDaniel P. Berrange for (i = 0; i < (stripes - 1); i++) {
995a95e0fcSDaniel P. Berrange if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
10057b9f113SDaniel P. Berrangé return -1;
1015a95e0fcSDaniel P. Berrange }
1025a95e0fcSDaniel P. Berrange
1035a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen,
1045a95e0fcSDaniel P. Berrange out + (i * blocklen),
1055a95e0fcSDaniel P. Berrange block,
1065a95e0fcSDaniel P. Berrange block);
1075a95e0fcSDaniel P. Berrange if (qcrypto_afsplit_hash(hash, blocklen, block,
1085a95e0fcSDaniel P. Berrange errp) < 0) {
10957b9f113SDaniel P. Berrangé return -1;
1105a95e0fcSDaniel P. Berrange }
1115a95e0fcSDaniel P. Berrange }
1125a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen,
1135a95e0fcSDaniel P. Berrange in,
1145a95e0fcSDaniel P. Berrange block,
1155a95e0fcSDaniel P. Berrange out + (i * blocklen));
11657b9f113SDaniel P. Berrangé return 0;
1175a95e0fcSDaniel P. Berrange }
1185a95e0fcSDaniel P. Berrange
1195a95e0fcSDaniel P. Berrange
qcrypto_afsplit_decode(QCryptoHashAlgo hash,size_t blocklen,uint32_t stripes,const uint8_t * in,uint8_t * out,Error ** errp)120*ef834aa2SMarkus Armbruster int qcrypto_afsplit_decode(QCryptoHashAlgo hash,
1215a95e0fcSDaniel P. Berrange size_t blocklen,
1225a95e0fcSDaniel P. Berrange uint32_t stripes,
1235a95e0fcSDaniel P. Berrange const uint8_t *in,
1245a95e0fcSDaniel P. Berrange uint8_t *out,
1255a95e0fcSDaniel P. Berrange Error **errp)
1265a95e0fcSDaniel P. Berrange {
12757b9f113SDaniel P. Berrangé g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
1285a95e0fcSDaniel P. Berrange size_t i;
1295a95e0fcSDaniel P. Berrange
1305a95e0fcSDaniel P. Berrange for (i = 0; i < (stripes - 1); i++) {
1315a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen,
1325a95e0fcSDaniel P. Berrange in + (i * blocklen),
1335a95e0fcSDaniel P. Berrange block,
1345a95e0fcSDaniel P. Berrange block);
1355a95e0fcSDaniel P. Berrange if (qcrypto_afsplit_hash(hash, blocklen, block,
1365a95e0fcSDaniel P. Berrange errp) < 0) {
13757b9f113SDaniel P. Berrangé return -1;
1385a95e0fcSDaniel P. Berrange }
1395a95e0fcSDaniel P. Berrange }
1405a95e0fcSDaniel P. Berrange
1415a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen,
1425a95e0fcSDaniel P. Berrange in + (i * blocklen),
1435a95e0fcSDaniel P. Berrange block,
1445a95e0fcSDaniel P. Berrange out);
14557b9f113SDaniel P. Berrangé return 0;
1465a95e0fcSDaniel P. Berrange }
147