xref: /qemu/crypto/afsplit.c (revision 6402cbbb)
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 
32 static 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 
44 static 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 
90 int 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 
127 int 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