]> git.proxmox.com Git - mirror_qemu.git/blob - crypto/block.c
Merge remote-tracking branch 'remotes/berrange/tags/pull-qcrypto-2016-03-17-3' into...
[mirror_qemu.git] / crypto / block.c
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 "crypto/blockpriv.h"
23 #include "crypto/block-qcow.h"
24 #include "crypto/block-luks.h"
25
26 static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
27 [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
28 [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
29 };
30
31
32 bool qcrypto_block_has_format(QCryptoBlockFormat format,
33 const uint8_t *buf,
34 size_t len)
35 {
36 const QCryptoBlockDriver *driver;
37
38 if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
39 !qcrypto_block_drivers[format]) {
40 return false;
41 }
42
43 driver = qcrypto_block_drivers[format];
44
45 return driver->has_format(buf, len);
46 }
47
48
49 QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
50 QCryptoBlockReadFunc readfunc,
51 void *opaque,
52 unsigned int flags,
53 Error **errp)
54 {
55 QCryptoBlock *block = g_new0(QCryptoBlock, 1);
56
57 block->format = options->format;
58
59 if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
60 !qcrypto_block_drivers[options->format]) {
61 error_setg(errp, "Unsupported block driver %d", options->format);
62 g_free(block);
63 return NULL;
64 }
65
66 block->driver = qcrypto_block_drivers[options->format];
67
68 if (block->driver->open(block, options,
69 readfunc, opaque, flags, errp) < 0) {
70 g_free(block);
71 return NULL;
72 }
73
74 return block;
75 }
76
77
78 QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
79 QCryptoBlockInitFunc initfunc,
80 QCryptoBlockWriteFunc writefunc,
81 void *opaque,
82 Error **errp)
83 {
84 QCryptoBlock *block = g_new0(QCryptoBlock, 1);
85
86 block->format = options->format;
87
88 if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
89 !qcrypto_block_drivers[options->format]) {
90 error_setg(errp, "Unsupported block driver %d", options->format);
91 g_free(block);
92 return NULL;
93 }
94
95 block->driver = qcrypto_block_drivers[options->format];
96
97 if (block->driver->create(block, options, initfunc,
98 writefunc, opaque, errp) < 0) {
99 g_free(block);
100 return NULL;
101 }
102
103 return block;
104 }
105
106
107 int qcrypto_block_decrypt(QCryptoBlock *block,
108 uint64_t startsector,
109 uint8_t *buf,
110 size_t len,
111 Error **errp)
112 {
113 return block->driver->decrypt(block, startsector, buf, len, errp);
114 }
115
116
117 int qcrypto_block_encrypt(QCryptoBlock *block,
118 uint64_t startsector,
119 uint8_t *buf,
120 size_t len,
121 Error **errp)
122 {
123 return block->driver->encrypt(block, startsector, buf, len, errp);
124 }
125
126
127 QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
128 {
129 return block->cipher;
130 }
131
132
133 QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
134 {
135 return block->ivgen;
136 }
137
138
139 QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
140 {
141 return block->kdfhash;
142 }
143
144
145 uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
146 {
147 return block->payload_offset;
148 }
149
150
151 void qcrypto_block_free(QCryptoBlock *block)
152 {
153 if (!block) {
154 return;
155 }
156
157 block->driver->cleanup(block);
158
159 qcrypto_cipher_free(block->cipher);
160 qcrypto_ivgen_free(block->ivgen);
161 g_free(block);
162 }
163
164
165 int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
166 size_t niv,
167 QCryptoIVGen *ivgen,
168 int sectorsize,
169 uint64_t startsector,
170 uint8_t *buf,
171 size_t len,
172 Error **errp)
173 {
174 uint8_t *iv;
175 int ret = -1;
176
177 iv = niv ? g_new0(uint8_t, niv) : NULL;
178
179 while (len > 0) {
180 size_t nbytes;
181 if (niv) {
182 if (qcrypto_ivgen_calculate(ivgen,
183 startsector,
184 iv, niv,
185 errp) < 0) {
186 goto cleanup;
187 }
188
189 if (qcrypto_cipher_setiv(cipher,
190 iv, niv,
191 errp) < 0) {
192 goto cleanup;
193 }
194 }
195
196 nbytes = len > sectorsize ? sectorsize : len;
197 if (qcrypto_cipher_decrypt(cipher, buf, buf,
198 nbytes, errp) < 0) {
199 goto cleanup;
200 }
201
202 startsector++;
203 buf += nbytes;
204 len -= nbytes;
205 }
206
207 ret = 0;
208 cleanup:
209 g_free(iv);
210 return ret;
211 }
212
213
214 int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
215 size_t niv,
216 QCryptoIVGen *ivgen,
217 int sectorsize,
218 uint64_t startsector,
219 uint8_t *buf,
220 size_t len,
221 Error **errp)
222 {
223 uint8_t *iv;
224 int ret = -1;
225
226 iv = niv ? g_new0(uint8_t, niv) : NULL;
227
228 while (len > 0) {
229 size_t nbytes;
230 if (niv) {
231 if (qcrypto_ivgen_calculate(ivgen,
232 startsector,
233 iv, niv,
234 errp) < 0) {
235 goto cleanup;
236 }
237
238 if (qcrypto_cipher_setiv(cipher,
239 iv, niv,
240 errp) < 0) {
241 goto cleanup;
242 }
243 }
244
245 nbytes = len > sectorsize ? sectorsize : len;
246 if (qcrypto_cipher_encrypt(cipher, buf, buf,
247 nbytes, errp) < 0) {
248 goto cleanup;
249 }
250
251 startsector++;
252 buf += nbytes;
253 len -= nbytes;
254 }
255
256 ret = 0;
257 cleanup:
258 g_free(iv);
259 return ret;
260 }