xref: /openbmc/qemu/crypto/block.c (revision 0e39bb022b5fa8c11964968885f3263c02ce42b0)
1 /*
2  * QEMU Crypto block device encryption
3  *
4  * Copyright (c) 2015-2016 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "crypto/blockpriv.h"
24 #include "crypto/block-qcow.h"
25 #include "crypto/block-luks.h"
26 
27 static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
28     [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
29     [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
30 };
31 
32 
33 bool qcrypto_block_has_format(QCryptoBlockFormat format,
34                               const uint8_t *buf,
35                               size_t len)
36 {
37     const QCryptoBlockDriver *driver;
38 
39     if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
40         !qcrypto_block_drivers[format]) {
41         return false;
42     }
43 
44     driver = qcrypto_block_drivers[format];
45 
46     return driver->has_format(buf, len);
47 }
48 
49 
50 QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
51                                  QCryptoBlockReadFunc readfunc,
52                                  void *opaque,
53                                  unsigned int flags,
54                                  Error **errp)
55 {
56     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
57 
58     block->format = options->format;
59 
60     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
61         !qcrypto_block_drivers[options->format]) {
62         error_setg(errp, "Unsupported block driver %d", options->format);
63         g_free(block);
64         return NULL;
65     }
66 
67     block->driver = qcrypto_block_drivers[options->format];
68 
69     if (block->driver->open(block, options,
70                             readfunc, opaque, flags, errp) < 0) {
71         g_free(block);
72         return NULL;
73     }
74 
75     return block;
76 }
77 
78 
79 QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
80                                    QCryptoBlockInitFunc initfunc,
81                                    QCryptoBlockWriteFunc writefunc,
82                                    void *opaque,
83                                    Error **errp)
84 {
85     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
86 
87     block->format = options->format;
88 
89     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
90         !qcrypto_block_drivers[options->format]) {
91         error_setg(errp, "Unsupported block driver %d", options->format);
92         g_free(block);
93         return NULL;
94     }
95 
96     block->driver = qcrypto_block_drivers[options->format];
97 
98     if (block->driver->create(block, options, initfunc,
99                               writefunc, opaque, errp) < 0) {
100         g_free(block);
101         return NULL;
102     }
103 
104     return block;
105 }
106 
107 
108 QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
109                                          Error **errp)
110 {
111     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
112 
113     info->format = block->format;
114 
115     if (block->driver->get_info &&
116         block->driver->get_info(block, info, errp) < 0) {
117         g_free(info);
118         return NULL;
119     }
120 
121     return info;
122 }
123 
124 
125 int qcrypto_block_decrypt(QCryptoBlock *block,
126                           uint64_t startsector,
127                           uint8_t *buf,
128                           size_t len,
129                           Error **errp)
130 {
131     return block->driver->decrypt(block, startsector, buf, len, errp);
132 }
133 
134 
135 int qcrypto_block_encrypt(QCryptoBlock *block,
136                           uint64_t startsector,
137                           uint8_t *buf,
138                           size_t len,
139                           Error **errp)
140 {
141     return block->driver->encrypt(block, startsector, buf, len, errp);
142 }
143 
144 
145 QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
146 {
147     return block->cipher;
148 }
149 
150 
151 QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
152 {
153     return block->ivgen;
154 }
155 
156 
157 QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
158 {
159     return block->kdfhash;
160 }
161 
162 
163 uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
164 {
165     return block->payload_offset;
166 }
167 
168 
169 void qcrypto_block_free(QCryptoBlock *block)
170 {
171     if (!block) {
172         return;
173     }
174 
175     block->driver->cleanup(block);
176 
177     qcrypto_cipher_free(block->cipher);
178     qcrypto_ivgen_free(block->ivgen);
179     g_free(block);
180 }
181 
182 
183 int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
184                                  size_t niv,
185                                  QCryptoIVGen *ivgen,
186                                  int sectorsize,
187                                  uint64_t startsector,
188                                  uint8_t *buf,
189                                  size_t len,
190                                  Error **errp)
191 {
192     uint8_t *iv;
193     int ret = -1;
194 
195     iv = niv ? g_new0(uint8_t, niv) : NULL;
196 
197     while (len > 0) {
198         size_t nbytes;
199         if (niv) {
200             if (qcrypto_ivgen_calculate(ivgen,
201                                         startsector,
202                                         iv, niv,
203                                         errp) < 0) {
204                 goto cleanup;
205             }
206 
207             if (qcrypto_cipher_setiv(cipher,
208                                      iv, niv,
209                                      errp) < 0) {
210                 goto cleanup;
211             }
212         }
213 
214         nbytes = len > sectorsize ? sectorsize : len;
215         if (qcrypto_cipher_decrypt(cipher, buf, buf,
216                                    nbytes, errp) < 0) {
217             goto cleanup;
218         }
219 
220         startsector++;
221         buf += nbytes;
222         len -= nbytes;
223     }
224 
225     ret = 0;
226  cleanup:
227     g_free(iv);
228     return ret;
229 }
230 
231 
232 int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
233                                  size_t niv,
234                                  QCryptoIVGen *ivgen,
235                                  int sectorsize,
236                                  uint64_t startsector,
237                                  uint8_t *buf,
238                                  size_t len,
239                                  Error **errp)
240 {
241     uint8_t *iv;
242     int ret = -1;
243 
244     iv = niv ? g_new0(uint8_t, niv) : NULL;
245 
246     while (len > 0) {
247         size_t nbytes;
248         if (niv) {
249             if (qcrypto_ivgen_calculate(ivgen,
250                                         startsector,
251                                         iv, niv,
252                                         errp) < 0) {
253                 goto cleanup;
254             }
255 
256             if (qcrypto_cipher_setiv(cipher,
257                                      iv, niv,
258                                      errp) < 0) {
259                 goto cleanup;
260             }
261         }
262 
263         nbytes = len > sectorsize ? sectorsize : len;
264         if (qcrypto_cipher_encrypt(cipher, buf, buf,
265                                    nbytes, errp) < 0) {
266             goto cleanup;
267         }
268 
269         startsector++;
270         buf += nbytes;
271         len -= nbytes;
272     }
273 
274     ret = 0;
275  cleanup:
276     g_free(iv);
277     return ret;
278 }
279