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        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        g_free(out);
  83    }
  84
  85    return 0;
  86}
  87
  88
  89int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
  90                           size_t blocklen,
  91                           uint32_t stripes,
  92                           const uint8_t *in,
  93                           uint8_t *out,
  94                           Error **errp)
  95{
  96    uint8_t *block = g_new0(uint8_t, blocklen);
  97    size_t i;
  98    int ret = -1;
  99
 100    for (i = 0; i < (stripes - 1); i++) {
 101        if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
 102            goto cleanup;
 103        }
 104
 105        qcrypto_afsplit_xor(blocklen,
 106                            out + (i * blocklen),
 107                            block,
 108                            block);
 109        if (qcrypto_afsplit_hash(hash, blocklen, block,
 110                                 errp) < 0) {
 111            goto cleanup;
 112        }
 113    }
 114    qcrypto_afsplit_xor(blocklen,
 115                        in,
 116                        block,
 117                        out + (i * blocklen));
 118    ret = 0;
 119
 120 cleanup:
 121    g_free(block);
 122    return ret;
 123}
 124
 125
 126int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
 127                           size_t blocklen,
 128                           uint32_t stripes,
 129                           const uint8_t *in,
 130                           uint8_t *out,
 131                           Error **errp)
 132{
 133    uint8_t *block = g_new0(uint8_t, blocklen);
 134    size_t i;
 135    int ret = -1;
 136
 137    for (i = 0; i < (stripes - 1); i++) {
 138        qcrypto_afsplit_xor(blocklen,
 139                            in + (i * blocklen),
 140                            block,
 141                            block);
 142        if (qcrypto_afsplit_hash(hash, blocklen, block,
 143                                 errp) < 0) {
 144            goto cleanup;
 145        }
 146    }
 147
 148    qcrypto_afsplit_xor(blocklen,
 149                        in + (i * blocklen),
 150                        block,
 151                        out);
 152
 153    ret = 0;
 154
 155 cleanup:
 156    g_free(block);
 157    return ret;
 158}
 159