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