qemu/crypto/afsplit.c
<<
>>
Prefs
   1/*
   2 * QEMU Crypto anti forensic information splitter
   3 *
   4 * Copyright (c) 2015-2016 Red Hat, Inc.
   5 *
   6 * Derived from cryptsetup package lib/luks1/af.c
   7 *
   8 * Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
   9 * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License
  13 * as published by the Free Software Foundation; either version 2
  14 * of the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu/bswap.h"
  27#include "crypto/afsplit.h"
  28#include "crypto/random.h"
  29
  30
  31static void qcrypto_afsplit_xor(size_t blocklen,
  32                                const uint8_t *in1,
  33                                const uint8_t *in2,
  34                                uint8_t *out)
  35{
  36    size_t i;
  37    for (i = 0; i < blocklen; i++) {
  38        out[i] = in1[i] ^ in2[i];
  39    }
  40}
  41
  42
  43static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
  44                                size_t blocklen,
  45                                uint8_t *block,
  46                                Error **errp)
  47{
  48    size_t digestlen = qcrypto_hash_digest_len(hash);
  49
  50    size_t hashcount = blocklen / digestlen;
  51    size_t finallen = blocklen % digestlen;
  52    uint32_t i;
  53
  54    if (finallen) {
  55        hashcount++;
  56    } else {
  57        finallen = digestlen;
  58    }
  59
  60    for (i = 0; i < hashcount; i++) {
  61        g_autofree uint8_t *out = NULL;
  62        size_t outlen = 0;
  63        uint32_t iv = cpu_to_be32(i);
  64        struct iovec in[] = {
  65            { .iov_base = &iv,
  66              .iov_len = sizeof(iv) },
  67            { .iov_base = block + (i * digestlen),
  68              .iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
  69        };
  70
  71        if (qcrypto_hash_bytesv(hash,
  72                                in,
  73                                G_N_ELEMENTS(in),
  74                                &out, &outlen,
  75                                errp) < 0) {
  76            return -1;
  77        }
  78
  79        assert(outlen == digestlen);
  80        memcpy(block + (i * digestlen), out,
  81               (i == (hashcount - 1)) ? finallen : digestlen);
  82    }
  83
  84    return 0;
  85}
  86
  87
  88int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
  89                           size_t blocklen,
  90                           uint32_t stripes,
  91                           const uint8_t *in,
  92                           uint8_t *out,
  93                           Error **errp)
  94{
  95    g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
  96    size_t i;
  97
  98    for (i = 0; i < (stripes - 1); i++) {
  99        if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
 100            return -1;
 101        }
 102
 103        qcrypto_afsplit_xor(blocklen,
 104                            out + (i * blocklen),
 105                            block,
 106                            block);
 107        if (qcrypto_afsplit_hash(hash, blocklen, block,
 108                                 errp) < 0) {
 109            return -1;
 110        }
 111    }
 112    qcrypto_afsplit_xor(blocklen,
 113                        in,
 114                        block,
 115                        out + (i * blocklen));
 116    return 0;
 117}
 118
 119
 120int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
 121                           size_t blocklen,
 122                           uint32_t stripes,
 123                           const uint8_t *in,
 124                           uint8_t *out,
 125                           Error **errp)
 126{
 127    g_autofree uint8_t *block = g_new0(uint8_t, blocklen);
 128    size_t i;
 129
 130    for (i = 0; i < (stripes - 1); i++) {
 131        qcrypto_afsplit_xor(blocklen,
 132                            in + (i * blocklen),
 133                            block,
 134                            block);
 135        if (qcrypto_afsplit_hash(hash, blocklen, block,
 136                                 errp) < 0) {
 137            return -1;
 138        }
 139    }
 140
 141    qcrypto_afsplit_xor(blocklen,
 142                        in + (i * blocklen),
 143                        block,
 144                        out);
 145    return 0;
 146}
 147