xref: /openbmc/qemu/crypto/block.c (revision 04e3aabd)
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                                  const char *optprefix,
52                                  QCryptoBlockReadFunc readfunc,
53                                  void *opaque,
54                                  unsigned int flags,
55                                  Error **errp)
56 {
57     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
58 
59     block->format = options->format;
60 
61     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
62         !qcrypto_block_drivers[options->format]) {
63         error_setg(errp, "Unsupported block driver %s",
64                    QCryptoBlockFormat_str(options->format));
65         g_free(block);
66         return NULL;
67     }
68 
69     block->driver = qcrypto_block_drivers[options->format];
70 
71     if (block->driver->open(block, options, optprefix,
72                             readfunc, opaque, flags, errp) < 0) {
73         g_free(block);
74         return NULL;
75     }
76 
77     return block;
78 }
79 
80 
81 QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
82                                    const char *optprefix,
83                                    QCryptoBlockInitFunc initfunc,
84                                    QCryptoBlockWriteFunc writefunc,
85                                    void *opaque,
86                                    Error **errp)
87 {
88     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
89 
90     block->format = options->format;
91 
92     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
93         !qcrypto_block_drivers[options->format]) {
94         error_setg(errp, "Unsupported block driver %s",
95                    QCryptoBlockFormat_str(options->format));
96         g_free(block);
97         return NULL;
98     }
99 
100     block->driver = qcrypto_block_drivers[options->format];
101 
102     if (block->driver->create(block, options, optprefix, initfunc,
103                               writefunc, opaque, errp) < 0) {
104         g_free(block);
105         return NULL;
106     }
107 
108     return block;
109 }
110 
111 
112 QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
113                                          Error **errp)
114 {
115     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
116 
117     info->format = block->format;
118 
119     if (block->driver->get_info &&
120         block->driver->get_info(block, info, errp) < 0) {
121         g_free(info);
122         return NULL;
123     }
124 
125     return info;
126 }
127 
128 
129 int qcrypto_block_decrypt(QCryptoBlock *block,
130                           uint64_t startsector,
131                           uint8_t *buf,
132                           size_t len,
133                           Error **errp)
134 {
135     return block->driver->decrypt(block, startsector, buf, len, errp);
136 }
137 
138 
139 int qcrypto_block_encrypt(QCryptoBlock *block,
140                           uint64_t startsector,
141                           uint8_t *buf,
142                           size_t len,
143                           Error **errp)
144 {
145     return block->driver->encrypt(block, startsector, buf, len, errp);
146 }
147 
148 
149 QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
150 {
151     return block->cipher;
152 }
153 
154 
155 QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
156 {
157     return block->ivgen;
158 }
159 
160 
161 QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
162 {
163     return block->kdfhash;
164 }
165 
166 
167 uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
168 {
169     return block->payload_offset;
170 }
171 
172 
173 void qcrypto_block_free(QCryptoBlock *block)
174 {
175     if (!block) {
176         return;
177     }
178 
179     block->driver->cleanup(block);
180 
181     qcrypto_cipher_free(block->cipher);
182     qcrypto_ivgen_free(block->ivgen);
183     g_free(block);
184 }
185 
186 
187 int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
188                                  size_t niv,
189                                  QCryptoIVGen *ivgen,
190                                  int sectorsize,
191                                  uint64_t startsector,
192                                  uint8_t *buf,
193                                  size_t len,
194                                  Error **errp)
195 {
196     uint8_t *iv;
197     int ret = -1;
198 
199     iv = niv ? g_new0(uint8_t, niv) : NULL;
200 
201     while (len > 0) {
202         size_t nbytes;
203         if (niv) {
204             if (qcrypto_ivgen_calculate(ivgen,
205                                         startsector,
206                                         iv, niv,
207                                         errp) < 0) {
208                 goto cleanup;
209             }
210 
211             if (qcrypto_cipher_setiv(cipher,
212                                      iv, niv,
213                                      errp) < 0) {
214                 goto cleanup;
215             }
216         }
217 
218         nbytes = len > sectorsize ? sectorsize : len;
219         if (qcrypto_cipher_decrypt(cipher, buf, buf,
220                                    nbytes, errp) < 0) {
221             goto cleanup;
222         }
223 
224         startsector++;
225         buf += nbytes;
226         len -= nbytes;
227     }
228 
229     ret = 0;
230  cleanup:
231     g_free(iv);
232     return ret;
233 }
234 
235 
236 int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
237                                  size_t niv,
238                                  QCryptoIVGen *ivgen,
239                                  int sectorsize,
240                                  uint64_t startsector,
241                                  uint8_t *buf,
242                                  size_t len,
243                                  Error **errp)
244 {
245     uint8_t *iv;
246     int ret = -1;
247 
248     iv = niv ? g_new0(uint8_t, niv) : NULL;
249 
250     while (len > 0) {
251         size_t nbytes;
252         if (niv) {
253             if (qcrypto_ivgen_calculate(ivgen,
254                                         startsector,
255                                         iv, niv,
256                                         errp) < 0) {
257                 goto cleanup;
258             }
259 
260             if (qcrypto_cipher_setiv(cipher,
261                                      iv, niv,
262                                      errp) < 0) {
263                 goto cleanup;
264             }
265         }
266 
267         nbytes = len > sectorsize ? sectorsize : len;
268         if (qcrypto_cipher_encrypt(cipher, buf, buf,
269                                    nbytes, errp) < 0) {
270             goto cleanup;
271         }
272 
273         startsector++;
274         buf += nbytes;
275         len -= nbytes;
276     }
277 
278     ret = 0;
279  cleanup:
280     g_free(iv);
281     return ret;
282 }
283