1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
|
/*
* QEMU Crypto block device encryption
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_BLOCK_H
#define QCRYPTO_BLOCK_H
#include "crypto/cipher.h"
#include "crypto/ivgen.h"
typedef struct QCryptoBlock QCryptoBlock;
/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions
* and QCryptoBlockOpenOptions in qapi/crypto.json */
typedef int (*QCryptoBlockReadFunc)(QCryptoBlock *block,
size_t offset,
uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp);
typedef int (*QCryptoBlockInitFunc)(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp);
typedef int (*QCryptoBlockWriteFunc)(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp);
/**
* qcrypto_block_has_format:
* @format: the encryption format
* @buf: the data from head of the volume
* @len: the length of @buf in bytes
*
* Given @len bytes of data from the head of a storage volume
* in @buf, probe to determine if the volume has the encryption
* format specified in @format.
*
* Returns: true if the data in @buf matches @format
*/
bool qcrypto_block_has_format(QCryptoBlockFormat format,
const uint8_t *buf,
size_t buflen);
typedef enum {
QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0),
} QCryptoBlockOpenFlags;
/**
* qcrypto_block_open:
* @options: the encryption options
* @optprefix: name prefix for options
* @readfunc: callback for reading data from the volume
* @opaque: data to pass to @readfunc
* @flags: bitmask of QCryptoBlockOpenFlags values
* @n_threads: allow concurrent I/O from up to @n_threads threads
* @errp: pointer to a NULL-initialized error object
*
* Create a new block encryption object for an existing
* storage volume encrypted with format identified by
* the parameters in @options.
*
* This will use @readfunc to initialize the encryption
* context based on the volume header(s), extracting the
* master key(s) as required.
*
* If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then
* the open process will be optimized to skip any parts
* that are only required to perform I/O. In particular
* this would usually avoid the need to decrypt any
* master keys. The only thing that can be done with
* the resulting QCryptoBlock object would be to query
* metadata such as the payload offset. There will be
* no cipher or ivgen objects available.
*
* If any part of initializing the encryption context
* fails an error will be returned. This could be due
* to the volume being in the wrong format, a cipher
* or IV generator algorithm that is not supported,
* or incorrect passphrases.
*
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
size_t n_threads,
Error **errp);
/**
* qcrypto_block_create:
* @options: the encryption options
* @optprefix: name prefix for options
* @initfunc: callback for initializing volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @initfunc and @writefunc
* @errp: pointer to a NULL-initialized error object
*
* Create a new block encryption object for initializing
* a storage volume to be encrypted with format identified
* by the parameters in @options.
*
* This method will allocate space for a new volume header
* using @initfunc and then write header data using @writefunc,
* generating new master keys, etc as required. Any existing
* data present on the volume will be irrevocably destroyed.
*
* If any part of initializing the encryption context
* fails an error will be returned. This could be due
* to the volume being in the wrong format, a cipher
* or IV generator algorithm that is not supported,
* or incorrect passphrases.
*
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
Error **errp);
/**
* qcrypto_block_amend_options:
* @block: the block encryption object
*
* @readfunc: callback for reading data from the volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @readfunc and @writefunc
* @options: the new/amended encryption options
* @force: hint for the driver to allow unsafe operation
* @errp: error pointer
*
* Changes the crypto options of the encryption format
*
*/
int qcrypto_block_amend_options(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
QCryptoBlockAmendOptions *options,
bool force,
Error **errp);
/**
* qcrypto_block_calculate_payload_offset:
* @create_opts: the encryption options
* @optprefix: name prefix for options
* @len: output for number of header bytes before payload
* @errp: pointer to a NULL-initialized error object
*
* Calculate the number of header bytes before the payload in an encrypted
* storage volume. The header is an area before the payload that is reserved
* for encryption metadata.
*
* Returns: true on success, false on error
*/
bool
qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
const char *optprefix,
size_t *len,
Error **errp);
/**
* qcrypto_block_get_info:
* @block: the block encryption object
* @errp: pointer to a NULL-initialized error object
*
* Get information about the configuration options for the
* block encryption object. This includes details such as
* the cipher algorithms, modes, and initialization vector
* generators.
*
* Returns: a block encryption info object, or NULL on error
*/
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
Error **errp);
/**
* @qcrypto_block_decrypt:
* @block: the block encryption object
* @offset: the position at which @iov was read
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Decrypt @len bytes of cipher text in @buf, writing
* plain text back into @buf. @len and @offset must be
* a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_decrypt(QCryptoBlock *block,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
/**
* @qcrypto_block_encrypt:
* @block: the block encryption object
* @offset: the position at which @iov will be written
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Encrypt @len bytes of plain text in @buf, writing
* cipher text back into @buf. @len and @offset must be
* a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_encrypt(QCryptoBlock *block,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
/**
* qcrypto_block_get_cipher:
* @block: the block encryption object
*
* Get the cipher to use for payload encryption
*
* Returns: the cipher object
*/
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block);
/**
* qcrypto_block_get_ivgen:
* @block: the block encryption object
*
* Get the initialization vector generator to use for
* payload encryption
*
* Returns: the IV generator object
*/
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block);
/**
* qcrypto_block_get_kdf_hash:
* @block: the block encryption object
*
* Get the hash algorithm used with the key derivation
* function
*
* Returns: the hash algorithm
*/
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
/**
* qcrypto_block_get_payload_offset:
* @block: the block encryption object
*
* Get the offset to the payload indicated by the
* encryption header, in bytes.
*
* Returns: the payload offset in bytes
*/
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
/**
* qcrypto_block_get_sector_size:
* @block: the block encryption object
*
* Get the size of sectors used for payload encryption. A new
* IV is used at the start of each sector. The encryption
* sector size is not required to match the sector size of the
* underlying storage. For example LUKS will always use a 512
* byte sector size, even if the volume is on a disk with 4k
* sectors.
*
* Returns: the sector in bytes
*/
uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
/**
* qcrypto_block_free:
* @block: the block encryption object
*
* Release all resources associated with the encryption
* object
*/
void qcrypto_block_free(QCryptoBlock *block);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
#endif /* QCRYPTO_BLOCK_H */
|