-
Notifications
You must be signed in to change notification settings - Fork 211
/
Copy pathprotected_files.h
320 lines (284 loc) · 9.69 KB
/
protected_files.h
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
316
317
318
319
320
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2020 Invisible Things Lab
* Rafal Wojdyla <[email protected]>
* Copyright (C) 2019 Intel Corporation
*/
/* See README.rst for protected files overview */
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define PF_NODE_SIZE 4096U
/*! Size of IV for AES-GCM */
#define PF_IV_SIZE 12
/*! Size of MAC fields */
#define PF_MAC_SIZE 16
/*! Size of the AES-GCM encryption key */
#define PF_KEY_SIZE 16
/*! Size of the nonce used in KDF (Key Derivation Function) */
#define PF_NONCE_SIZE 32
typedef uint8_t pf_iv_t[PF_IV_SIZE];
typedef uint8_t pf_mac_t[PF_MAC_SIZE];
typedef uint8_t pf_key_t[PF_KEY_SIZE];
typedef uint8_t pf_nonce_t[PF_NONCE_SIZE];
// convenience macros to print out some mac fingerprint: printf( "some text " MAC_PRINTF_PATTERN "
// yet other text", MAC_PRINTF_ARGS(mac) );
#define MAC_PRINTF_PATTERN "0x%02x%02x%02x%02x..."
#define MAC_PRINTF_ARGS(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3]
typedef enum _pf_status_t {
PF_STATUS_SUCCESS = 0,
PF_STATUS_UNKNOWN_ERROR = -1,
PF_STATUS_UNINITIALIZED = -2,
PF_STATUS_INVALID_PARAMETER = -3,
PF_STATUS_INVALID_MODE = -4,
PF_STATUS_NO_MEMORY = -5,
PF_STATUS_INVALID_VERSION = -6,
PF_STATUS_INVALID_HEADER = -7,
PF_STATUS_INVALID_PATH = -8,
PF_STATUS_MAC_MISMATCH = -9,
PF_STATUS_NOT_IMPLEMENTED = -10,
PF_STATUS_CALLBACK_FAILED = -11,
PF_STATUS_PATH_TOO_LONG = -12,
PF_STATUS_RECOVERY_NEEDED = -13,
PF_STATUS_FLUSH_ERROR = -14,
PF_STATUS_CRYPTO_ERROR = -15,
PF_STATUS_CORRUPTED = -16,
PF_STATUS_WRITE_TO_DISK_FAILED = -17,
} pf_status_t;
#define PF_SUCCESS(status) ((status) == PF_STATUS_SUCCESS)
#define PF_FAILURE(status) ((status) != PF_STATUS_SUCCESS)
/*! PF open modes */
typedef enum _pf_file_mode_t {
PF_FILE_MODE_READ = 1,
PF_FILE_MODE_WRITE = 2,
} pf_file_mode_t;
/*! Opaque file handle type, interpreted by callbacks as necessary */
typedef void* pf_handle_t;
/*! Context representing an open protected file */
typedef struct pf_context pf_context_t;
/*!
* \brief File read callback.
*
* \param handle File handle.
* \param[out] buffer Buffer to read to.
* \param offset Offset to read from.
* \param size Number of bytes to read.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_read_f)(pf_handle_t handle, void* buffer, uint64_t offset, size_t size);
/*!
* \brief File write callback.
*
* \param handle File handle.
* \param buffer Buffer to write from.
* \param offset Offset to write to.
* \param size Number of bytes to write.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_write_f)(pf_handle_t handle, const void* buffer, uint64_t offset,
size_t size);
/*!
* \brief File sync callback.
*
* \param handle File handle.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_fsync_f)(pf_handle_t handle);
/*!
* \brief File truncate callback.
*
* \param handle File handle.
* \param size Target file size.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_truncate_f)(pf_handle_t handle, uint64_t size);
/*!
* \brief Debug print callback.
*
* \param msg Message to print.
*/
typedef void (*pf_debug_f)(const char* msg);
/*!
* \brief AES-CMAC callback used for key derivation.
*
* \param key AES-GCM key.
* \param input Plaintext data.
* \param input_size Size of \p input in bytes.
* \param[out] mac MAC computed for \p input.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_aes_cmac_f)(const pf_key_t* key, const void* input, size_t input_size,
pf_mac_t* mac);
/*!
* \brief AES-GCM encrypt callback.
*
* \param key AES-GCM key.
* \param iv Initialization vector.
* \param aad (optional) Additional authenticated data.
* \param aad_size Size of \p aad in bytes.
* \param input Plaintext data.
* \param input_size Size of \p input in bytes.
* \param[out] output Buffer for encrypted data (size: \p input_size).
* \param[out] mac MAC computed for \p input and \p aad.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_aes_gcm_encrypt_f)(const pf_key_t* key, const pf_iv_t* iv, const void* aad,
size_t aad_size, const void* input, size_t input_size,
void* output, pf_mac_t* mac);
/*!
* \brief AES-GCM decrypt callback.
*
* \param key AES-GCM key.
* \param iv Initialization vector.
* \param aad (optional) Additional authenticated data.
* \param aad_size Size of \p aad in bytes.
* \param input Encrypted data.
* \param input_size Size of \p input in bytes.
* \param[out] output Buffer for decrypted data (size: \p input_size).
* \param mac Expected MAC.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_aes_gcm_decrypt_f)(const pf_key_t* key, const pf_iv_t* iv, const void* aad,
size_t aad_size, const void* input, size_t input_size,
void* output, const pf_mac_t* mac);
/*!
* \brief Cryptographic random number generator callback.
*
* \param[out] buffer Buffer to fill with random bytes.
* \param size Size of \p buffer in bytes.
*
* \returns PF status.
*/
typedef pf_status_t (*pf_random_f)(uint8_t* buffer, size_t size);
/*!
* \brief Initialize I/O callbacks.
*
* \param read_f File read callback.
* \param write_f File write callback.
* \param fsync_f File sync callback.
* \param truncate_f File truncate callback.
* \param aes_cmac_f AES-CMAC callback.
* \param aes_gcm_encrypt_f AES-GCM encrypt callback.
* \param aes_gcm_decrypt_f AES-GCM decrypt callback.
* \param random_f Cryptographic random number generator callback.
* \param debug_f (optional) Debug print callback.
*
* Must be called before any actual APIs.
*/
void pf_set_callbacks(pf_read_f read_f, pf_write_f write_f, pf_fsync_f fsync_f,
pf_truncate_f truncate_f, pf_aes_cmac_f aes_cmac_f,
pf_aes_gcm_encrypt_f aes_gcm_encrypt_f,
pf_aes_gcm_decrypt_f aes_gcm_decrypt_f, pf_random_f random_f,
pf_debug_f debug_f);
/* Public API */
/*!
* \brief Convert error code to error message.
*
* \param err Error code.
*
* \returns Error message.
*/
const char* pf_strerror(int err);
/*!
* \brief Open a protected file.
*
* \param handle Open underlying file handle.
* \param path Path to the file. If NULL and \p create is false, don't check path
* for validity.
* \param underlying_size Underlying file size.
* \param mode Access mode.
* \param create Overwrite file contents if true.
* \param key Wrap key.
* \param opening_root_mac If non-NULL, !create & successfull open, returns root-hash of file
* \param[out] context PF context for later calls.
*
* \returns PF status.
*/
pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_size,
pf_file_mode_t mode, bool create, const pf_key_t* key,
pf_mac_t* opening_root_mac, pf_context_t** context);
/*!
* \brief Close a protected file and commit all changes to disk.
*
* \param pf PF context.
* \param closing_root_mac If non-NULL, returns root-hash of file at closing time
*
* \returns PF status.
*/
pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_mac);
/*!
* \brief Read from a protected file.
*
* \param pf PF context.
* \param offset Data offset to read from.
* \param size Number of bytes to read.
* \param[out] output Destination buffer.
* \param[out] bytes_read Number of bytes actually read.
*
* \returns PF status.
*/
pf_status_t pf_read(pf_context_t* pf, uint64_t offset, size_t size, void* output,
size_t* bytes_read);
/*!
* \brief Write to a protected file.
*
* \param pf PF context.
* \param offset Data offset to write to.
* \param size Number of bytes to write.
* \param input Source buffer.
*
* \returns PF status.
*/
pf_status_t pf_write(pf_context_t* pf, uint64_t offset, size_t size, const void* input);
/*!
* \brief Get data size of a PF.
*
* \param pf PF context.
* \param[out] size Data size of \p pf.
*
* \returns PF status.
*/
pf_status_t pf_get_size(pf_context_t* pf, uint64_t* size);
/*!
* \brief Set data size of a PF.
*
* \param pf PF context.
* \param size Data size to set.
*
* \returns PF status.
*
* If the file is extended, added bytes are zero.
*/
pf_status_t pf_set_size(pf_context_t* pf, uint64_t size);
/*!
* \brief Rename a PF.
*
* \param pf PF context.
* \param new_path New file path.
* \param new_root_mac if non-NULL, returns new root-hash of file
*
* Updates the path inside protected file header, and flushes all changes. The caller is responsible
* for renaming the underlying file.
*/
pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root_mac);
/*!
* \brief Flush any pending data of a protected file to disk.
*
* \param pf PF context.
*
* \returns PF status.
*/
pf_status_t pf_flush(pf_context_t* pf);
/*!
* \brief Set protected file state as corrupted
*
* \param pf PF context.
*/
void pf_set_corrupted(pf_context_t* pf);