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 * 11*e361a772SThomas 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 * 16*e361a772SThomas 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 19*e361a772SThomas Huth * General Public License for more details. 205a95e0fcSDaniel P. Berrange * 21*e361a772SThomas Huth * You should have received a copy of the GNU General Public License 22*e361a772SThomas 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 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 435a95e0fcSDaniel P. Berrange static int qcrypto_afsplit_hash(QCryptoHashAlgorithm 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++) { 615a95e0fcSDaniel P. Berrange 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 g_free(out); 835a95e0fcSDaniel P. Berrange } 845a95e0fcSDaniel P. Berrange 855a95e0fcSDaniel P. Berrange return 0; 865a95e0fcSDaniel P. Berrange } 875a95e0fcSDaniel P. Berrange 885a95e0fcSDaniel P. Berrange 895a95e0fcSDaniel P. Berrange int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash, 905a95e0fcSDaniel P. Berrange size_t blocklen, 915a95e0fcSDaniel P. Berrange uint32_t stripes, 925a95e0fcSDaniel P. Berrange const uint8_t *in, 935a95e0fcSDaniel P. Berrange uint8_t *out, 945a95e0fcSDaniel P. Berrange Error **errp) 955a95e0fcSDaniel P. Berrange { 965a95e0fcSDaniel P. Berrange uint8_t *block = g_new0(uint8_t, blocklen); 975a95e0fcSDaniel P. Berrange size_t i; 985a95e0fcSDaniel P. Berrange int ret = -1; 995a95e0fcSDaniel P. Berrange 1005a95e0fcSDaniel P. Berrange for (i = 0; i < (stripes - 1); i++) { 1015a95e0fcSDaniel P. Berrange if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) { 1025a95e0fcSDaniel P. Berrange goto cleanup; 1035a95e0fcSDaniel P. Berrange } 1045a95e0fcSDaniel P. Berrange 1055a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen, 1065a95e0fcSDaniel P. Berrange out + (i * blocklen), 1075a95e0fcSDaniel P. Berrange block, 1085a95e0fcSDaniel P. Berrange block); 1095a95e0fcSDaniel P. Berrange if (qcrypto_afsplit_hash(hash, blocklen, block, 1105a95e0fcSDaniel P. Berrange errp) < 0) { 1115a95e0fcSDaniel P. Berrange goto cleanup; 1125a95e0fcSDaniel P. Berrange } 1135a95e0fcSDaniel P. Berrange } 1145a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen, 1155a95e0fcSDaniel P. Berrange in, 1165a95e0fcSDaniel P. Berrange block, 1175a95e0fcSDaniel P. Berrange out + (i * blocklen)); 1185a95e0fcSDaniel P. Berrange ret = 0; 1195a95e0fcSDaniel P. Berrange 1205a95e0fcSDaniel P. Berrange cleanup: 1215a95e0fcSDaniel P. Berrange g_free(block); 1225a95e0fcSDaniel P. Berrange return ret; 1235a95e0fcSDaniel P. Berrange } 1245a95e0fcSDaniel P. Berrange 1255a95e0fcSDaniel P. Berrange 1265a95e0fcSDaniel P. Berrange int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash, 1275a95e0fcSDaniel P. Berrange size_t blocklen, 1285a95e0fcSDaniel P. Berrange uint32_t stripes, 1295a95e0fcSDaniel P. Berrange const uint8_t *in, 1305a95e0fcSDaniel P. Berrange uint8_t *out, 1315a95e0fcSDaniel P. Berrange Error **errp) 1325a95e0fcSDaniel P. Berrange { 1335a95e0fcSDaniel P. Berrange uint8_t *block = g_new0(uint8_t, blocklen); 1345a95e0fcSDaniel P. Berrange size_t i; 1355a95e0fcSDaniel P. Berrange int ret = -1; 1365a95e0fcSDaniel P. Berrange 1375a95e0fcSDaniel P. Berrange for (i = 0; i < (stripes - 1); i++) { 1385a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen, 1395a95e0fcSDaniel P. Berrange in + (i * blocklen), 1405a95e0fcSDaniel P. Berrange block, 1415a95e0fcSDaniel P. Berrange block); 1425a95e0fcSDaniel P. Berrange if (qcrypto_afsplit_hash(hash, blocklen, block, 1435a95e0fcSDaniel P. Berrange errp) < 0) { 1445a95e0fcSDaniel P. Berrange goto cleanup; 1455a95e0fcSDaniel P. Berrange } 1465a95e0fcSDaniel P. Berrange } 1475a95e0fcSDaniel P. Berrange 1485a95e0fcSDaniel P. Berrange qcrypto_afsplit_xor(blocklen, 1495a95e0fcSDaniel P. Berrange in + (i * blocklen), 1505a95e0fcSDaniel P. Berrange block, 1515a95e0fcSDaniel P. Berrange out); 1525a95e0fcSDaniel P. Berrange 1535a95e0fcSDaniel P. Berrange ret = 0; 1545a95e0fcSDaniel P. Berrange 1555a95e0fcSDaniel P. Berrange cleanup: 1565a95e0fcSDaniel P. Berrange g_free(block); 1575a95e0fcSDaniel P. Berrange return ret; 1585a95e0fcSDaniel P. Berrange } 159