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 | |
31 | static 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 | |
43 | static 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 | |
88 | int 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 | |
120 | int 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 | |