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 library 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 library 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 * Lesser General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU Lesser General Public
  22 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  23 *
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "qemu/bswap.h"
  28#include "crypto/afsplit.h"
  29#include "crypto/random.h"
  30
  31
  32static void qcrypto_afsplit_xor(size_t blocklen,
  33                                const uint8_t *in1,
  34                                const uint8_t *in2,
  35                                uint8_t *out)
  36{
  37    size_t i;
  38    for (i = 0; i < blocklen; i++) {
  39        out[i] = in1[i] ^ in2[i];
  40    }
  41}
  42
  43
  44static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
  45                                size_t blocklen,
  46                                uint8_t *block,
  47                                Error **errp)
  48{
  49    size_t digestlen = qcrypto_hash_digest_len(hash);
  50
  51    size_t hashcount = blocklen / digestlen;
  52    size_t finallen = blocklen % digestlen;
  53    uint32_t i;
  54
  55    if (finallen) {
  56        hashcount++;
  57    } else {
  58        finallen = digestlen;
  59    }
  60
  61    for (i = 0; i < hashcount; i++) {
  62        uint8_t *out = NULL;
  63        size_t outlen = 0;
  64        uint32_t iv = cpu_to_be32(i);
  65        struct iovec in[] = {
  66            { .iov_base = &iv,
  67              .iov_len = sizeof(iv) },
  68            { .iov_base = block + (i * digestlen),
  69              .iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
  70        };
  71
  72        if (qcrypto_hash_bytesv(hash,
  73                                in,
  74                                G_N_ELEMENTS(in),
  75                                &out, &outlen,
  76                                errp) < 0) {
  77            return -1;
  78        }
  79
  80        assert(outlen == digestlen);
  81        memcpy(block + (i * digestlen), out,
  82               (i == (hashcount - 1)) ? finallen : digestlen);
  83        g_free(out);
  84    }
  85
  86    return 0;
  87}
  88
  89
  90int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
  91                           size_t blocklen,
  92                           uint32_t stripes,
  93                           const uint8_t *in,
  94                           uint8_t *out,
  95                           Error **errp)
  96{
  97    uint8_t *block = g_new0(uint8_t, blocklen);
  98    size_t i;
  99    int ret = -1;
 100
 101    for (i = 0; i < (stripes - 1); i++) {
 102        if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
 103            goto cleanup;
 104        }
 105
 106        qcrypto_afsplit_xor(blocklen,
 107                            out + (i * blocklen),
 108                            block,
 109                            block);
 110        if (qcrypto_afsplit_hash(hash, blocklen, block,
 111                                 errp) < 0) {
 112            goto cleanup;
 113        }
 114    }
 115    qcrypto_afsplit_xor(blocklen,
 116                        in,
 117                        block,
 118                        out + (i * blocklen));
 119    ret = 0;
 120
 121 cleanup:
 122    g_free(block);
 123    return ret;
 124}
 125
 126
 127int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
 128                           size_t blocklen,
 129                           uint32_t stripes,
 130                           const uint8_t *in,
 131                           uint8_t *out,
 132                           Error **errp)
 133{
 134    uint8_t *block = g_new0(uint8_t, blocklen);
 135    size_t i;
 136    int ret = -1;
 137
 138    for (i = 0; i < (stripes - 1); i++) {
 139        qcrypto_afsplit_xor(blocklen,
 140                            in + (i * blocklen),
 141                            block,
 142                            block);
 143        if (qcrypto_afsplit_hash(hash, blocklen, block,
 144                                 errp) < 0) {
 145            goto cleanup;
 146        }
 147    }
 148
 149    qcrypto_afsplit_xor(blocklen,
 150                        in + (i * blocklen),
 151                        block,
 152                        out);
 153
 154    ret = 0;
 155
 156 cleanup:
 157    g_free(block);
 158    return ret;
 159}
 160