/src/cryptsetup/lib/luks2/luks2_json_format.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * LUKS - Linux Unified Key Setup v2, LUKS2 header format code |
4 | | * |
5 | | * Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved. |
6 | | * Copyright (C) 2015-2025 Milan Broz |
7 | | */ |
8 | | |
9 | | #include "luks2_internal.h" |
10 | | #include <uuid/uuid.h> |
11 | | |
12 | | struct area { |
13 | | uint64_t offset; |
14 | | uint64_t length; |
15 | | }; |
16 | | |
17 | | static size_t get_area_size(size_t keylength) |
18 | 0 | { |
19 | | /* for now it is AF_split_sectors */ |
20 | 0 | return size_round_up(keylength * 4000, 4096); |
21 | 0 | } |
22 | | |
23 | | static size_t get_min_offset(struct luks2_hdr *hdr) |
24 | 0 | { |
25 | 0 | return 2 * hdr->hdr_size; |
26 | 0 | } |
27 | | |
28 | | static size_t get_max_offset(struct luks2_hdr *hdr) |
29 | 0 | { |
30 | 0 | return LUKS2_hdr_and_areas_size(hdr); |
31 | 0 | } |
32 | | |
33 | | int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr, |
34 | | uint64_t *area_offset, uint64_t *area_length) |
35 | 0 | { |
36 | 0 | struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX+1] = {}; |
37 | 0 | int i, j, k, area_i; |
38 | 0 | size_t valid_offset, offset, length; |
39 | | |
40 | | /* fill area offset + length table */ |
41 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) { |
42 | 0 | if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length)) |
43 | 0 | continue; |
44 | 0 | areas[i].length = 0; |
45 | 0 | areas[i].offset = 0; |
46 | 0 | } |
47 | | |
48 | | /* sort table */ |
49 | 0 | k = 0; /* index in sorted table */ |
50 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) { |
51 | 0 | offset = get_max_offset(hdr) ?: UINT64_MAX; |
52 | 0 | area_i = -1; |
53 | | /* search for the smallest offset in table */ |
54 | 0 | for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++) |
55 | 0 | if (areas[j].offset && areas[j].offset <= offset) { |
56 | 0 | area_i = j; |
57 | 0 | offset = areas[j].offset; |
58 | 0 | } |
59 | |
|
60 | 0 | if (area_i >= 0) { |
61 | 0 | sorted_areas[k].length = areas[area_i].length; |
62 | 0 | sorted_areas[k].offset = areas[area_i].offset; |
63 | 0 | areas[area_i].length = 0; |
64 | 0 | areas[area_i].offset = 0; |
65 | 0 | k++; |
66 | 0 | } |
67 | 0 | } |
68 | |
|
69 | 0 | sorted_areas[LUKS2_KEYSLOTS_MAX].offset = get_max_offset(hdr); |
70 | 0 | sorted_areas[LUKS2_KEYSLOTS_MAX].length = 1; |
71 | | |
72 | | /* search for the gap we can use */ |
73 | 0 | length = valid_offset = 0; |
74 | 0 | offset = get_min_offset(hdr); |
75 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX+1; i++) { |
76 | | /* skip empty */ |
77 | 0 | if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0) |
78 | 0 | continue; |
79 | | |
80 | | /* found bigger gap than the last one */ |
81 | 0 | if ((offset < sorted_areas[i].offset) && (sorted_areas[i].offset - offset) > length) { |
82 | 0 | length = sorted_areas[i].offset - offset; |
83 | 0 | valid_offset = offset; |
84 | 0 | } |
85 | | |
86 | | /* move beyond allocated area */ |
87 | 0 | offset = sorted_areas[i].offset + sorted_areas[i].length; |
88 | 0 | } |
89 | | |
90 | | /* this search 'algorithm' does not work with unaligned areas */ |
91 | 0 | assert(length == size_round_up(length, 4096)); |
92 | 0 | assert(valid_offset == size_round_up(valid_offset, 4096)); |
93 | |
|
94 | 0 | if (!length) { |
95 | 0 | log_dbg(cd, "Not enough space in header keyslot area."); |
96 | 0 | return -EINVAL; |
97 | 0 | } |
98 | | |
99 | 0 | log_dbg(cd, "Found largest free area %zu -> %zu", valid_offset, length + valid_offset); |
100 | |
|
101 | 0 | *area_offset = valid_offset; |
102 | 0 | *area_length = length; |
103 | |
|
104 | 0 | return 0; |
105 | 0 | } |
106 | | |
107 | | int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr, |
108 | | size_t keylength, uint64_t *area_offset, uint64_t *area_length) |
109 | 0 | { |
110 | 0 | struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX] = {}; |
111 | 0 | int i, j, k, area_i; |
112 | 0 | size_t offset, length; |
113 | | |
114 | | /* fill area offset + length table */ |
115 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) { |
116 | 0 | if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length)) |
117 | 0 | continue; |
118 | 0 | areas[i].length = 0; |
119 | 0 | areas[i].offset = 0; |
120 | 0 | } |
121 | | |
122 | | /* sort table */ |
123 | 0 | k = 0; /* index in sorted table */ |
124 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) { |
125 | 0 | offset = get_max_offset(hdr) ?: UINT64_MAX; |
126 | 0 | area_i = -1; |
127 | | /* search for the smallest offset in table */ |
128 | 0 | for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++) |
129 | 0 | if (areas[j].offset && areas[j].offset <= offset) { |
130 | 0 | area_i = j; |
131 | 0 | offset = areas[j].offset; |
132 | 0 | } |
133 | |
|
134 | 0 | if (area_i >= 0) { |
135 | 0 | sorted_areas[k].length = areas[area_i].length; |
136 | 0 | sorted_areas[k].offset = areas[area_i].offset; |
137 | 0 | areas[area_i].length = 0; |
138 | 0 | areas[area_i].offset = 0; |
139 | 0 | k++; |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | /* search for the gap we can use */ |
144 | 0 | offset = get_min_offset(hdr); |
145 | 0 | length = get_area_size(keylength); |
146 | 0 | for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) { |
147 | | /* skip empty */ |
148 | 0 | if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0) |
149 | 0 | continue; |
150 | | |
151 | | /* enough space before the used area */ |
152 | 0 | if ((offset < sorted_areas[i].offset) && ((offset + length) <= sorted_areas[i].offset)) |
153 | 0 | break; |
154 | | |
155 | | /* both offset and length are already aligned to 4096 bytes */ |
156 | 0 | offset = sorted_areas[i].offset + sorted_areas[i].length; |
157 | 0 | } |
158 | |
|
159 | 0 | if ((offset + length) > get_max_offset(hdr)) { |
160 | 0 | log_dbg(cd, "Not enough space in header keyslot area."); |
161 | 0 | return -EINVAL; |
162 | 0 | } |
163 | | |
164 | 0 | log_dbg(cd, "Found area %zu -> %zu", offset, length + offset); |
165 | |
|
166 | 0 | if (area_offset) |
167 | 0 | *area_offset = offset; |
168 | 0 | if (area_length) |
169 | 0 | *area_length = length; |
170 | |
|
171 | 0 | return 0; |
172 | 0 | } |
173 | | |
174 | | int LUKS2_check_metadata_area_size(uint64_t metadata_size) |
175 | 5.29k | { |
176 | | /* see LUKS2_HDR2_OFFSETS */ |
177 | 5.29k | return (metadata_size != 0x004000 && |
178 | 5.29k | metadata_size != 0x008000 && metadata_size != 0x010000 && |
179 | 30 | metadata_size != 0x020000 && metadata_size != 0x040000 && |
180 | 30 | metadata_size != 0x080000 && metadata_size != 0x100000 && |
181 | 30 | metadata_size != 0x200000 && metadata_size != 0x400000); |
182 | 5.29k | } |
183 | | |
184 | | int LUKS2_check_keyslots_area_size(uint64_t keyslots_size) |
185 | 5.26k | { |
186 | 5.26k | return (MISALIGNED_4K(keyslots_size) || |
187 | 5.26k | keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE); |
188 | 5.26k | } |
189 | | |
190 | | int LUKS2_generate_hdr( |
191 | | struct crypt_device *cd, |
192 | | struct luks2_hdr *hdr, |
193 | | const struct volume_key *vk, |
194 | | const char *cipher_spec, |
195 | | const char *integrity, |
196 | | uint32_t integrity_key_size, /* in bytes, only if separate (HMAC) */ |
197 | | const char *uuid, |
198 | | unsigned int sector_size, /* in bytes */ |
199 | | uint64_t data_offset, /* in bytes */ |
200 | | uint64_t metadata_size_bytes, |
201 | | uint64_t keyslots_size_bytes, |
202 | | uint64_t device_size_bytes, |
203 | | uint32_t opal_segment_number, |
204 | | uint32_t opal_key_size) |
205 | 0 | { |
206 | 0 | json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config; |
207 | 0 | uuid_t partitionUuid; |
208 | 0 | int r, digest; |
209 | |
|
210 | 0 | assert(cipher_spec || (opal_key_size > 0 && device_size_bytes)); |
211 | |
|
212 | 0 | hdr->hdr_size = metadata_size_bytes; |
213 | |
|
214 | 0 | log_dbg(cd, "Formatting LUKS2 with JSON metadata area %" PRIu64 |
215 | 0 | " bytes and keyslots area %" PRIu64 " bytes.", |
216 | 0 | metadata_size_bytes - LUKS2_HDR_BIN_LEN, keyslots_size_bytes); |
217 | |
|
218 | 0 | if (keyslots_size_bytes < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN)) |
219 | 0 | log_std(cd, _("WARNING: keyslots area (%" PRIu64 " bytes) is very small," |
220 | 0 | " available LUKS2 keyslot count is very limited.\n"), |
221 | 0 | keyslots_size_bytes); |
222 | |
|
223 | 0 | hdr->seqid = 1; |
224 | 0 | hdr->version = 2; |
225 | 0 | memset(hdr->label, 0, LUKS2_LABEL_L); |
226 | 0 | strcpy(hdr->checksum_alg, "sha256"); |
227 | 0 | crypt_random_get(cd, (char*)hdr->salt1, LUKS2_SALT_L, CRYPT_RND_SALT); |
228 | 0 | crypt_random_get(cd, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT); |
229 | |
|
230 | 0 | if (uuid && uuid_parse(uuid, partitionUuid) == -1) { |
231 | 0 | log_err(cd, _("Wrong LUKS UUID format provided.")); |
232 | 0 | return -EINVAL; |
233 | 0 | } |
234 | 0 | if (!uuid) |
235 | 0 | uuid_generate(partitionUuid); |
236 | |
|
237 | 0 | uuid_unparse(partitionUuid, hdr->uuid); |
238 | |
|
239 | 0 | hdr->jobj = json_object_new_object(); |
240 | 0 | if (!hdr->jobj) { |
241 | 0 | r = -ENOMEM; |
242 | 0 | goto err; |
243 | 0 | } |
244 | | |
245 | 0 | jobj_keyslots = json_object_new_object(); |
246 | 0 | if (!jobj_keyslots) { |
247 | 0 | r = -ENOMEM; |
248 | 0 | goto err; |
249 | 0 | } |
250 | | |
251 | 0 | json_object_object_add(hdr->jobj, "keyslots", jobj_keyslots); |
252 | 0 | json_object_object_add(hdr->jobj, "tokens", json_object_new_object()); |
253 | 0 | jobj_segments = json_object_new_object(); |
254 | 0 | if (!jobj_segments) { |
255 | 0 | r = -ENOMEM; |
256 | 0 | goto err; |
257 | 0 | } |
258 | | |
259 | 0 | json_object_object_add(hdr->jobj, "segments", jobj_segments); |
260 | 0 | json_object_object_add(hdr->jobj, "digests", json_object_new_object()); |
261 | 0 | jobj_config = json_object_new_object(); |
262 | 0 | if (!jobj_config) { |
263 | 0 | r = -ENOMEM; |
264 | 0 | goto err; |
265 | 0 | } |
266 | | |
267 | 0 | json_object_object_add(hdr->jobj, "config", jobj_config); |
268 | |
|
269 | 0 | digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk); |
270 | 0 | if (digest < 0) { |
271 | 0 | r = -EINVAL; |
272 | 0 | goto err; |
273 | 0 | } |
274 | | |
275 | 0 | if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0) { |
276 | 0 | r = -EINVAL; |
277 | 0 | goto err; |
278 | 0 | } |
279 | | |
280 | 0 | if (!opal_key_size) |
281 | 0 | jobj_segment = json_segment_create_crypt(data_offset, 0, |
282 | 0 | NULL, cipher_spec, |
283 | 0 | integrity, integrity_key_size, |
284 | 0 | sector_size, 0); |
285 | 0 | else if (opal_key_size && cipher_spec) |
286 | 0 | jobj_segment = json_segment_create_opal_crypt(data_offset, &device_size_bytes, |
287 | 0 | opal_segment_number, opal_key_size, 0, |
288 | 0 | cipher_spec, integrity, |
289 | 0 | sector_size, 0); |
290 | 0 | else |
291 | 0 | jobj_segment = json_segment_create_opal(data_offset, &device_size_bytes, |
292 | 0 | opal_segment_number, opal_key_size); |
293 | |
|
294 | 0 | if (!jobj_segment) { |
295 | 0 | r = -EINVAL; |
296 | 0 | goto err; |
297 | 0 | } |
298 | | |
299 | 0 | if (json_object_object_add_by_uint(jobj_segments, 0, jobj_segment)) { |
300 | 0 | json_object_put(jobj_segment); |
301 | 0 | r = -ENOMEM; |
302 | 0 | goto err; |
303 | 0 | } |
304 | | |
305 | 0 | json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size_bytes - LUKS2_HDR_BIN_LEN)); |
306 | 0 | json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size_bytes)); |
307 | |
|
308 | 0 | JSON_DBG(cd, hdr->jobj, "Header JSON:"); |
309 | 0 | return 0; |
310 | 0 | err: |
311 | 0 | json_object_put(hdr->jobj); |
312 | 0 | hdr->jobj = NULL; |
313 | 0 | return r; |
314 | 0 | } |
315 | | |
316 | | int LUKS2_wipe_header_areas(struct crypt_device *cd, |
317 | | struct luks2_hdr *hdr) |
318 | 0 | { |
319 | 0 | int r; |
320 | 0 | uint64_t device_size_bytes, length, offset; |
321 | 0 | size_t wipe_block = 1024 * 1024; |
322 | |
|
323 | 0 | if (!hdr || LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN)) |
324 | 0 | return -EINVAL; |
325 | | |
326 | 0 | r = device_size(crypt_metadata_device(cd), &device_size_bytes); |
327 | 0 | if (r < 0) |
328 | 0 | return -EINVAL; |
329 | | |
330 | | /* Wipe up to maximal allowed metadata size, but do not write beyond data offset. */ |
331 | 0 | length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE; |
332 | 0 | if (!length || length > LUKS2_HDR_MAX_MDA_SIZE) |
333 | 0 | length = LUKS2_HDR_MAX_MDA_SIZE; |
334 | | |
335 | | /* Also do not extend the device size yet (file backends) */ |
336 | 0 | if (length > device_size_bytes) |
337 | 0 | length = device_size_bytes; |
338 | |
|
339 | 0 | log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.", |
340 | 0 | 0ULL, length); |
341 | |
|
342 | 0 | r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0, |
343 | 0 | length, wipe_block, NULL, NULL); |
344 | 0 | if (r < 0) |
345 | 0 | return r; |
346 | | |
347 | | /* Allocate at least actual LUKS2 metadata size */ |
348 | 0 | r = device_check_size(cd, crypt_metadata_device(cd), |
349 | 0 | LUKS2_hdr_and_areas_size(hdr), 1); |
350 | 0 | if (r) |
351 | 0 | return r; |
352 | | |
353 | | /* Wipe keyslot area */ |
354 | 0 | offset = get_min_offset(hdr); |
355 | 0 | length = LUKS2_keyslots_size(hdr); |
356 | | |
357 | | /* |
358 | | * Skip keyslots area wipe in case it is not defined. |
359 | | * Otherwise we would wipe whole data device (length == 0) |
360 | | * starting at offset get_min_offset(hdr). |
361 | | */ |
362 | 0 | if (!length) |
363 | 0 | return 0; |
364 | | |
365 | 0 | log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.", |
366 | 0 | offset, length + offset); |
367 | |
|
368 | 0 | return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM, |
369 | 0 | offset, length, wipe_block, NULL, NULL); |
370 | 0 | } |
371 | | |
372 | | int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset) |
373 | 0 | { |
374 | 0 | json_object *jobj_config; |
375 | 0 | uint64_t keyslots_size; |
376 | |
|
377 | 0 | if (data_offset < get_min_offset(hdr)) |
378 | 0 | return 1; |
379 | | |
380 | 0 | keyslots_size = data_offset - get_min_offset(hdr); |
381 | | |
382 | | /* keep keyslots_size reasonable for custom data alignments */ |
383 | 0 | if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE) |
384 | 0 | keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE; |
385 | | |
386 | | /* keyslots size has to be 4 KiB aligned */ |
387 | 0 | keyslots_size -= (keyslots_size % 4096); |
388 | |
|
389 | 0 | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
390 | 0 | return 1; |
391 | | |
392 | 0 | json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size)); |
393 | 0 | return 0; |
394 | 0 | } |
395 | | |
396 | | int LUKS2_hdr_get_storage_params(struct crypt_device *cd, |
397 | | uint64_t alignment_offset_bytes, |
398 | | uint64_t alignment_bytes, |
399 | | uint64_t *ret_metadata_size_bytes, |
400 | | uint64_t *ret_keyslots_size_bytes, |
401 | | uint64_t *ret_data_offset_bytes) |
402 | 0 | { |
403 | 0 | uint64_t data_offset_bytes, keyslots_size_bytes, metadata_size_bytes, mdev_size_bytes; |
404 | |
|
405 | 0 | assert(cd); |
406 | 0 | assert(ret_metadata_size_bytes); |
407 | 0 | assert(ret_keyslots_size_bytes); |
408 | 0 | assert(ret_data_offset_bytes); |
409 | |
|
410 | 0 | metadata_size_bytes = crypt_get_metadata_size_bytes(cd); |
411 | 0 | keyslots_size_bytes = crypt_get_keyslots_size_bytes(cd); |
412 | 0 | data_offset_bytes = crypt_get_data_offset_sectors(cd) * SECTOR_SIZE; |
413 | |
|
414 | 0 | if (!metadata_size_bytes) |
415 | 0 | metadata_size_bytes = LUKS2_HDR_16K_LEN; |
416 | |
|
417 | 0 | if (data_offset_bytes && data_offset_bytes < 2 * metadata_size_bytes) { |
418 | 0 | log_err(cd, _("Requested data offset is too small.")); |
419 | 0 | return -EINVAL; |
420 | 0 | } |
421 | | |
422 | | /* Increase keyslot size according to data offset */ |
423 | 0 | if (!keyslots_size_bytes && data_offset_bytes) |
424 | 0 | keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes; |
425 | | |
426 | | /* keyslots size has to be 4 KiB aligned */ |
427 | 0 | keyslots_size_bytes -= (keyslots_size_bytes % 4096); |
428 | |
|
429 | 0 | if (keyslots_size_bytes > LUKS2_MAX_KEYSLOTS_SIZE) |
430 | 0 | keyslots_size_bytes = LUKS2_MAX_KEYSLOTS_SIZE; |
431 | |
|
432 | 0 | if (!keyslots_size_bytes) { |
433 | 0 | assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX); |
434 | 0 | keyslots_size_bytes = LUKS2_DEFAULT_HDR_SIZE - 2 * metadata_size_bytes; |
435 | | /* Decrease keyslots_size due to metadata device being too small */ |
436 | 0 | if (!device_size(crypt_metadata_device(cd), &mdev_size_bytes) && |
437 | 0 | ((keyslots_size_bytes + 2 * metadata_size_bytes) > mdev_size_bytes) && |
438 | 0 | device_fallocate(crypt_metadata_device(cd), keyslots_size_bytes + 2 * metadata_size_bytes) && |
439 | 0 | ((2 * metadata_size_bytes) <= mdev_size_bytes)) |
440 | 0 | keyslots_size_bytes = mdev_size_bytes - 2 * metadata_size_bytes; |
441 | 0 | } |
442 | | |
443 | | /* Decrease keyslots_size if we have smaller data_offset */ |
444 | 0 | if (data_offset_bytes && (keyslots_size_bytes + 2 * metadata_size_bytes) > data_offset_bytes) { |
445 | 0 | keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes; |
446 | 0 | log_dbg(cd, "Decreasing keyslot area size to %" PRIu64 |
447 | 0 | " bytes due to the requested data offset %" |
448 | 0 | PRIu64 " bytes.", keyslots_size_bytes, data_offset_bytes); |
449 | 0 | } |
450 | | |
451 | | /* Data offset has priority */ |
452 | 0 | if (!data_offset_bytes && alignment_bytes) { |
453 | 0 | data_offset_bytes = size_round_up(2 * metadata_size_bytes + keyslots_size_bytes, |
454 | 0 | (size_t)alignment_bytes); |
455 | 0 | data_offset_bytes += alignment_offset_bytes; |
456 | 0 | } |
457 | |
|
458 | 0 | if (crypt_get_metadata_size_bytes(cd) && (crypt_get_metadata_size_bytes(cd) != metadata_size_bytes)) |
459 | 0 | log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"), |
460 | 0 | metadata_size_bytes); |
461 | |
|
462 | 0 | if (crypt_get_keyslots_size_bytes(cd) && (crypt_get_keyslots_size_bytes(cd) != keyslots_size_bytes)) |
463 | 0 | log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PRIu64 " bytes.\n"), |
464 | 0 | keyslots_size_bytes); |
465 | |
|
466 | 0 | *ret_metadata_size_bytes = metadata_size_bytes; |
467 | 0 | *ret_keyslots_size_bytes = keyslots_size_bytes; |
468 | 0 | *ret_data_offset_bytes = data_offset_bytes; |
469 | |
|
470 | 0 | return 0; |
471 | 0 | } |