xref: /openbmc/qemu/crypto/afsplit.c (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
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