xref: /openbmc/qemu/crypto/afsplit.c (revision 58369e22cf971448411bfbc8c894b2addebe2111)
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  *
115a95e0fcSDaniel P. Berrange  * This library 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  *
165a95e0fcSDaniel P. Berrange  * This library 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
195a95e0fcSDaniel P. Berrange  * Lesser General Public License for more details.
205a95e0fcSDaniel P. Berrange  *
215a95e0fcSDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
225a95e0fcSDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
235a95e0fcSDaniel P. Berrange  *
245a95e0fcSDaniel P. Berrange  */
255a95e0fcSDaniel P. Berrange 
265a95e0fcSDaniel P. Berrange #include "qemu/osdep.h"
27*58369e22SPaolo Bonzini #include "qemu/bswap.h"
285a95e0fcSDaniel P. Berrange #include "crypto/afsplit.h"
295a95e0fcSDaniel P. Berrange #include "crypto/random.h"
305a95e0fcSDaniel P. Berrange 
315a95e0fcSDaniel P. Berrange 
325a95e0fcSDaniel P. Berrange static void qcrypto_afsplit_xor(size_t blocklen,
335a95e0fcSDaniel P. Berrange                                 const uint8_t *in1,
345a95e0fcSDaniel P. Berrange                                 const uint8_t *in2,
355a95e0fcSDaniel P. Berrange                                 uint8_t *out)
365a95e0fcSDaniel P. Berrange {
375a95e0fcSDaniel P. Berrange     size_t i;
385a95e0fcSDaniel P. Berrange     for (i = 0; i < blocklen; i++) {
395a95e0fcSDaniel P. Berrange         out[i] = in1[i] ^ in2[i];
405a95e0fcSDaniel P. Berrange     }
415a95e0fcSDaniel P. Berrange }
425a95e0fcSDaniel P. Berrange 
435a95e0fcSDaniel P. Berrange 
445a95e0fcSDaniel P. Berrange static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
455a95e0fcSDaniel P. Berrange                                 size_t blocklen,
465a95e0fcSDaniel P. Berrange                                 uint8_t *block,
475a95e0fcSDaniel P. Berrange                                 Error **errp)
485a95e0fcSDaniel P. Berrange {
495a95e0fcSDaniel P. Berrange     size_t digestlen = qcrypto_hash_digest_len(hash);
505a95e0fcSDaniel P. Berrange 
515a95e0fcSDaniel P. Berrange     size_t hashcount = blocklen / digestlen;
525a95e0fcSDaniel P. Berrange     size_t finallen = blocklen % digestlen;
535a95e0fcSDaniel P. Berrange     uint32_t i;
545a95e0fcSDaniel P. Berrange 
555a95e0fcSDaniel P. Berrange     if (finallen) {
565a95e0fcSDaniel P. Berrange         hashcount++;
575a95e0fcSDaniel P. Berrange     } else {
585a95e0fcSDaniel P. Berrange         finallen = digestlen;
595a95e0fcSDaniel P. Berrange     }
605a95e0fcSDaniel P. Berrange 
615a95e0fcSDaniel P. Berrange     for (i = 0; i < hashcount; i++) {
625a95e0fcSDaniel P. Berrange         uint8_t *out = NULL;
635a95e0fcSDaniel P. Berrange         size_t outlen = 0;
645a95e0fcSDaniel P. Berrange         uint32_t iv = cpu_to_be32(i);
655a95e0fcSDaniel P. Berrange         struct iovec in[] = {
665a95e0fcSDaniel P. Berrange             { .iov_base = &iv,
675a95e0fcSDaniel P. Berrange               .iov_len = sizeof(iv) },
685a95e0fcSDaniel P. Berrange             { .iov_base = block + (i * digestlen),
695a95e0fcSDaniel P. Berrange               .iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
705a95e0fcSDaniel P. Berrange         };
715a95e0fcSDaniel P. Berrange 
725a95e0fcSDaniel P. Berrange         if (qcrypto_hash_bytesv(hash,
735a95e0fcSDaniel P. Berrange                                 in,
745a95e0fcSDaniel P. Berrange                                 G_N_ELEMENTS(in),
755a95e0fcSDaniel P. Berrange                                 &out, &outlen,
765a95e0fcSDaniel P. Berrange                                 errp) < 0) {
775a95e0fcSDaniel P. Berrange             return -1;
785a95e0fcSDaniel P. Berrange         }
795a95e0fcSDaniel P. Berrange 
805a95e0fcSDaniel P. Berrange         assert(outlen == digestlen);
815a95e0fcSDaniel P. Berrange         memcpy(block + (i * digestlen), out,
825a95e0fcSDaniel P. Berrange                (i == (hashcount - 1)) ? finallen : digestlen);
835a95e0fcSDaniel P. Berrange         g_free(out);
845a95e0fcSDaniel P. Berrange     }
855a95e0fcSDaniel P. Berrange 
865a95e0fcSDaniel P. Berrange     return 0;
875a95e0fcSDaniel P. Berrange }
885a95e0fcSDaniel P. Berrange 
895a95e0fcSDaniel P. Berrange 
905a95e0fcSDaniel P. Berrange int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
915a95e0fcSDaniel P. Berrange                            size_t blocklen,
925a95e0fcSDaniel P. Berrange                            uint32_t stripes,
935a95e0fcSDaniel P. Berrange                            const uint8_t *in,
945a95e0fcSDaniel P. Berrange                            uint8_t *out,
955a95e0fcSDaniel P. Berrange                            Error **errp)
965a95e0fcSDaniel P. Berrange {
975a95e0fcSDaniel P. Berrange     uint8_t *block = g_new0(uint8_t, blocklen);
985a95e0fcSDaniel P. Berrange     size_t i;
995a95e0fcSDaniel P. Berrange     int ret = -1;
1005a95e0fcSDaniel P. Berrange 
1015a95e0fcSDaniel P. Berrange     for (i = 0; i < (stripes - 1); i++) {
1025a95e0fcSDaniel P. Berrange         if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
1035a95e0fcSDaniel P. Berrange             goto cleanup;
1045a95e0fcSDaniel P. Berrange         }
1055a95e0fcSDaniel P. Berrange 
1065a95e0fcSDaniel P. Berrange         qcrypto_afsplit_xor(blocklen,
1075a95e0fcSDaniel P. Berrange                             out + (i * blocklen),
1085a95e0fcSDaniel P. Berrange                             block,
1095a95e0fcSDaniel P. Berrange                             block);
1105a95e0fcSDaniel P. Berrange         if (qcrypto_afsplit_hash(hash, blocklen, block,
1115a95e0fcSDaniel P. Berrange                                  errp) < 0) {
1125a95e0fcSDaniel P. Berrange             goto cleanup;
1135a95e0fcSDaniel P. Berrange         }
1145a95e0fcSDaniel P. Berrange     }
1155a95e0fcSDaniel P. Berrange     qcrypto_afsplit_xor(blocklen,
1165a95e0fcSDaniel P. Berrange                         in,
1175a95e0fcSDaniel P. Berrange                         block,
1185a95e0fcSDaniel P. Berrange                         out + (i * blocklen));
1195a95e0fcSDaniel P. Berrange     ret = 0;
1205a95e0fcSDaniel P. Berrange 
1215a95e0fcSDaniel P. Berrange  cleanup:
1225a95e0fcSDaniel P. Berrange     g_free(block);
1235a95e0fcSDaniel P. Berrange     return ret;
1245a95e0fcSDaniel P. Berrange }
1255a95e0fcSDaniel P. Berrange 
1265a95e0fcSDaniel P. Berrange 
1275a95e0fcSDaniel P. Berrange int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
1285a95e0fcSDaniel P. Berrange                            size_t blocklen,
1295a95e0fcSDaniel P. Berrange                            uint32_t stripes,
1305a95e0fcSDaniel P. Berrange                            const uint8_t *in,
1315a95e0fcSDaniel P. Berrange                            uint8_t *out,
1325a95e0fcSDaniel P. Berrange                            Error **errp)
1335a95e0fcSDaniel P. Berrange {
1345a95e0fcSDaniel P. Berrange     uint8_t *block = g_new0(uint8_t, blocklen);
1355a95e0fcSDaniel P. Berrange     size_t i;
1365a95e0fcSDaniel P. Berrange     int ret = -1;
1375a95e0fcSDaniel P. Berrange 
1385a95e0fcSDaniel P. Berrange     for (i = 0; i < (stripes - 1); i++) {
1395a95e0fcSDaniel P. Berrange         qcrypto_afsplit_xor(blocklen,
1405a95e0fcSDaniel P. Berrange                             in + (i * blocklen),
1415a95e0fcSDaniel P. Berrange                             block,
1425a95e0fcSDaniel P. Berrange                             block);
1435a95e0fcSDaniel P. Berrange         if (qcrypto_afsplit_hash(hash, blocklen, block,
1445a95e0fcSDaniel P. Berrange                                  errp) < 0) {
1455a95e0fcSDaniel P. Berrange             goto cleanup;
1465a95e0fcSDaniel P. Berrange         }
1475a95e0fcSDaniel P. Berrange     }
1485a95e0fcSDaniel P. Berrange 
1495a95e0fcSDaniel P. Berrange     qcrypto_afsplit_xor(blocklen,
1505a95e0fcSDaniel P. Berrange                         in + (i * blocklen),
1515a95e0fcSDaniel P. Berrange                         block,
1525a95e0fcSDaniel P. Berrange                         out);
1535a95e0fcSDaniel P. Berrange 
1545a95e0fcSDaniel P. Berrange     ret = 0;
1555a95e0fcSDaniel P. Berrange 
1565a95e0fcSDaniel P. Berrange  cleanup:
1575a95e0fcSDaniel P. Berrange     g_free(block);
1585a95e0fcSDaniel P. Berrange     return ret;
1595a95e0fcSDaniel P. Berrange }
160