/* * QEMU Crypto anti forensic information splitter * * Copyright (c) 2015-2016 Red Hat, Inc. * * Derived from cryptsetup package lib/luks1/af.c * * Copyright (C) 2004, Clemens Fruhwirth * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "qemu/osdep.h" #include "qemu/bswap.h" #include "crypto/afsplit.h" #include "crypto/random.h" static void qcrypto_afsplit_xor(size_t blocklen, const uint8_t *in1, const uint8_t *in2, uint8_t *out) { size_t i; for (i = 0; i < blocklen; i++) { out[i] = in1[i] ^ in2[i]; } } static int qcrypto_afsplit_hash(QCryptoHashAlgo hash, size_t blocklen, uint8_t *block, Error **errp) { size_t digestlen = qcrypto_hash_digest_len(hash); size_t hashcount = blocklen / digestlen; size_t finallen = blocklen % digestlen; uint32_t i; if (finallen) { hashcount++; } else { finallen = digestlen; } for (i = 0; i < hashcount; i++) { g_autofree uint8_t *out = NULL; size_t outlen = 0; uint32_t iv = cpu_to_be32(i); struct iovec in[] = { { .iov_base = &iv, .iov_len = sizeof(iv) }, { .iov_base = block + (i * digestlen), .iov_len = (i == (hashcount - 1)) ? finallen : digestlen }, }; if (qcrypto_hash_bytesv(hash, in, G_N_ELEMENTS(in), &out, &outlen, errp) < 0) { return -1; } assert(outlen == digestlen); memcpy(block + (i * digestlen), out, (i == (hashcount - 1)) ? finallen : digestlen); } return 0; } int qcrypto_afsplit_encode(QCryptoHashAlgo hash, size_t blocklen, uint32_t stripes, const uint8_t *in, uint8_t *out, Error **errp) { g_autofree uint8_t *block = g_new0(uint8_t, blocklen); size_t i; for (i = 0; i < (stripes - 1); i++) { if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) { return -1; } qcrypto_afsplit_xor(blocklen, out + (i * blocklen), block, block); if (qcrypto_afsplit_hash(hash, blocklen, block, errp) < 0) { return -1; } } qcrypto_afsplit_xor(blocklen, in, block, out + (i * blocklen)); return 0; } int qcrypto_afsplit_decode(QCryptoHashAlgo hash, size_t blocklen, uint32_t stripes, const uint8_t *in, uint8_t *out, Error **errp) { g_autofree uint8_t *block = g_new0(uint8_t, blocklen); size_t i; for (i = 0; i < (stripes - 1); i++) { qcrypto_afsplit_xor(blocklen, in + (i * blocklen), block, block); if (qcrypto_afsplit_hash(hash, blocklen, block, errp) < 0) { return -1; } } qcrypto_afsplit_xor(blocklen, in + (i * blocklen), block, out); return 0; }