xref: /openbmc/qemu/crypto/afsplit.c (revision 5428e12d)
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 
qcrypto_afsplit_xor(size_t blocklen,const uint8_t * in1,const uint8_t * in2,uint8_t * out)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 
qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,size_t blocklen,uint8_t * block,Error ** errp)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 
qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,size_t blocklen,uint32_t stripes,const uint8_t * in,uint8_t * out,Error ** errp)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 
qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,size_t blocklen,uint32_t stripes,const uint8_t * in,uint8_t * out,Error ** errp)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