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