2 * cryptsetup LUKS2 custom mutator fuzz target
4 * Copyright (C) 2022-2023 Daniel Zatovic <daniel.zatovic@gmail.com>
5 * Copyright (C) 2022-2023 Red Hat, Inc. All rights reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "proto_to_luks2_converter.h"
26 #include "src/cryptsetup.h"
27 #include "luks2/luks2.h"
31 namespace LUKS2_proto {
33 std::string LUKS2ProtoConverter::string_uint64_to_string(const string_uint64 &str_u64) {
34 std::ostringstream os;
36 if (str_u64.negative())
39 if (str_u64.has_uint_num())
40 os << str_u64.uint_num();
41 else if (str_u64.has_string_num())
42 os << str_u64.string_num();
47 std::string LUKS2ProtoConverter::object_id_to_string(const object_id &oid) {
48 std::ostringstream os;
50 if (oid.has_int_id()) {
51 os << (oid.int_id() % 33) - 16;
52 } else if (oid.has_string_id()) {
53 os << oid.string_id();
59 std::string LUKS2ProtoConverter::hash_algorithm_to_string(const hash_algorithm type) {
68 std::string LUKS2ProtoConverter::keyslot_area_type_to_string(const keyslot_area_type type) {
70 case KEYSLOT_AREA_TYPE_RAW:
72 case KEYSLOT_AREA_TYPE_NONE:
74 case KEYSLOT_AREA_TYPE_JOURNAL:
76 case KEYSLOT_AREA_TYPE_CHECKSUM:
78 case KEYSLOT_AREA_TYPE_DATASHIFT:
83 void LUKS2ProtoConverter::generate_keyslot_area(struct json_object *jobj_area, const keyslot_area_description &keyslot_area_desc) {
85 if (keyslot_area_desc.has_type())
86 json_object_object_add(jobj_area, "type", json_object_new_string(keyslot_area_type_to_string(keyslot_area_desc.type()).c_str()));
87 if (keyslot_area_desc.has_offset())
88 json_object_object_add(jobj_area, "offset", json_object_new_string(string_uint64_to_string(keyslot_area_desc.offset()).c_str()));
89 if (keyslot_area_desc.has_size())
90 json_object_object_add(jobj_area, "size", json_object_new_string(string_uint64_to_string(keyslot_area_desc.size()).c_str()));
93 if (keyslot_area_desc.has_encryption())
94 json_object_object_add(jobj_area, "encryption", json_object_new_string(keyslot_area_desc.encryption().c_str()));
95 if (keyslot_area_desc.has_key_size())
96 json_object_object_add(jobj_area, "key_size", json_object_new_int(keyslot_area_desc.key_size()));
98 // checksum type fields
99 if (keyslot_area_desc.has_hash())
100 json_object_object_add(jobj_area, "hash", json_object_new_string(hash_algorithm_to_string(keyslot_area_desc.hash()).c_str()));
101 if (keyslot_area_desc.has_sector_size())
102 json_object_object_add(jobj_area, "sector_size", json_object_new_int(keyslot_area_desc.sector_size()));
104 // datashift type fields
105 if (keyslot_area_desc.has_shift_size())
106 json_object_object_add(jobj_area, "shift_size", json_object_new_string(string_uint64_to_string(keyslot_area_desc.shift_size()).c_str()));
109 std::string LUKS2ProtoConverter::keyslot_kdf_type_to_string(const keyslot_kdf_type type) {
111 case KEYSLOT_KDF_TYPE_PBKDF2:
113 case KEYSLOT_KDF_TYPE_ARGON2I:
115 case KEYSLOT_KDF_TYPE_ARGON2ID:
120 void LUKS2ProtoConverter::generate_keyslot_kdf(struct json_object *jobj_kdf, const keyslot_kdf_description &keyslot_kdf_desc) {
122 if (keyslot_kdf_desc.has_type())
123 json_object_object_add(jobj_kdf, "type", json_object_new_string(keyslot_kdf_type_to_string(keyslot_kdf_desc.type()).c_str()));
125 if (keyslot_kdf_desc.has_salt())
126 json_object_object_add(jobj_kdf, "salt", json_object_new_string(keyslot_kdf_desc.salt().c_str()));
128 json_object_object_add(jobj_kdf, "salt", json_object_new_string("6vz4xK7cjan92rDA5JF8O6Jk2HouV0O8DMB6GlztVk="));
131 if (keyslot_kdf_desc.has_hash())
132 json_object_object_add(jobj_kdf, "hash", json_object_new_string(hash_algorithm_to_string(keyslot_kdf_desc.hash()).c_str()));
133 if (keyslot_kdf_desc.has_iterations())
134 json_object_object_add(jobj_kdf, "iterations", json_object_new_int(keyslot_kdf_desc.iterations()));
136 // argon2i and argon2id types
137 if (keyslot_kdf_desc.has_time())
138 json_object_object_add(jobj_kdf, "time", json_object_new_int(keyslot_kdf_desc.time()));
139 if (keyslot_kdf_desc.has_memory())
140 json_object_object_add(jobj_kdf, "memory", json_object_new_int(keyslot_kdf_desc.memory()));
141 if (keyslot_kdf_desc.has_cpus())
142 json_object_object_add(jobj_kdf, "cpus", json_object_new_int(keyslot_kdf_desc.cpus()));
145 std::string LUKS2ProtoConverter::keyslot_af_type_to_string(const keyslot_af_type type) {
147 case KEYSLOT_AF_TYPE_LUKS1:
152 void LUKS2ProtoConverter::generate_keyslot_af(struct json_object *jobj_af, const keyslot_af_description &keyslot_af_desc) {
153 if (keyslot_af_desc.has_type())
154 json_object_object_add(jobj_af, "type", json_object_new_string(keyslot_af_type_to_string(keyslot_af_desc.type()).c_str()));
155 if (keyslot_af_desc.has_stripes())
156 json_object_object_add(jobj_af, "stripes", json_object_new_int(keyslot_af_desc.stripes()));
157 if (keyslot_af_desc.has_hash())
158 json_object_object_add(jobj_af, "hash", json_object_new_string(hash_algorithm_to_string(keyslot_af_desc.hash()).c_str()));
161 std::string LUKS2ProtoConverter::keyslot_type_to_string(const keyslot_type type) {
163 case KEYSLOT_TYPE_LUKS2:
165 case KEYSLOT_TYPE_REENCRYPT:
167 case KEYSLOT_TYPE_PLACEHOLDER:
168 return "placeholder";
172 std::string LUKS2ProtoConverter::reencrypt_keyslot_mode_to_string(const reencrypt_keyslot_mode mode) {
183 std::string LUKS2ProtoConverter::reencrypt_keyslot_direction_to_string(const reencrypt_keyslot_direction direction) {
185 case DIRECTION_FORWARD:
187 case DIRECTION_BACKWARD:
192 void LUKS2ProtoConverter::generate_keyslot(struct json_object *jobj_keyslots, const keyslot_description &keyslot_desc) {
193 struct json_object *jobj_keyslot, *jobj_area, *jobj_kdf, *jobj_af;
195 jobj_keyslot = json_object_new_object();
196 if (keyslot_desc.has_type())
197 json_object_object_add(jobj_keyslot, "type", json_object_new_string(keyslot_type_to_string(keyslot_desc.type()).c_str()));
198 if (keyslot_desc.has_key_size())
199 json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(keyslot_desc.key_size()));
200 if (keyslot_desc.has_priority())
201 json_object_object_add(jobj_keyslot, "priority", json_object_new_int(keyslot_desc.priority()));
202 if (keyslot_desc.has_mode())
203 json_object_object_add(jobj_keyslot, "mode", json_object_new_int(keyslot_desc.mode()));
204 if (keyslot_desc.has_direction())
205 json_object_object_add(jobj_keyslot, "direction", json_object_new_int(keyslot_desc.direction()));
208 if (keyslot_desc.has_area()) {
209 jobj_area = json_object_new_object();
210 generate_keyslot_area(jobj_area, keyslot_desc.area());
211 json_object_object_add(jobj_keyslot, "area", jobj_area);
215 if (keyslot_desc.has_kdf()) {
216 jobj_kdf = json_object_new_object();
217 generate_keyslot_kdf(jobj_kdf, keyslot_desc.kdf());
218 json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
222 if (keyslot_desc.has_af()) {
223 jobj_af = json_object_new_object();
224 generate_keyslot_af(jobj_af, keyslot_desc.af());
225 json_object_object_add(jobj_keyslot, "af", jobj_af);
228 json_object_object_add(jobj_keyslots, object_id_to_string(keyslot_desc.oid()).c_str(), jobj_keyslot);
231 void LUKS2ProtoConverter::generate_token(struct json_object *jobj_tokens, const token_description &token_desc) {
232 struct json_object *jobj_token, *jobj_keyslots;
233 jobj_token = json_object_new_object();
235 if (token_desc.has_type())
236 json_object_object_add(jobj_token, "type", json_object_new_string(token_desc.type().c_str()));
238 if (token_desc.has_key_description())
239 json_object_object_add(jobj_token, "key_description", json_object_new_string(token_desc.key_description().c_str()));
241 if (!token_desc.keyslots().empty()) {
242 jobj_keyslots = json_object_new_array();
244 for (const object_id& oid : token_desc.keyslots()) {
245 json_object_array_add(jobj_keyslots,
246 json_object_new_string(object_id_to_string(oid).c_str()));
249 /* Replace or add new keyslots array */
250 json_object_object_add(jobj_token, "keyslots", jobj_keyslots);
253 json_object_object_add(jobj_tokens, object_id_to_string(token_desc.oid()).c_str(), jobj_token);
256 void LUKS2ProtoConverter::generate_digest(struct json_object *jobj_digests, const digest_description &digest_desc) {
257 struct json_object *jobj_digest, *jobj_keyslots, *jobj_segments;
259 jobj_digest = json_object_new_object();
261 if (digest_desc.has_type())
262 json_object_object_add(jobj_digest, "type", json_object_new_string(keyslot_kdf_type_to_string(digest_desc.type()).c_str()));
264 if (!digest_desc.keyslots().empty()) {
265 jobj_keyslots = json_object_new_array();
267 for (const object_id& oid : digest_desc.keyslots()) {
268 json_object_array_add(jobj_keyslots,
269 json_object_new_string(object_id_to_string(oid).c_str()));
272 /* Replace or add new keyslots array */
273 json_object_object_add(jobj_digest, "keyslots", jobj_keyslots);
276 if (!digest_desc.segments().empty()) {
277 jobj_segments = json_object_new_array();
279 for (const object_id& oid : digest_desc.segments()) {
280 json_object_array_add(jobj_segments,
281 json_object_new_string(object_id_to_string(oid).c_str()));
284 /* Replace or add new segments array */
285 json_object_object_add(jobj_digest, "segments", jobj_segments);
288 if (digest_desc.has_salt())
289 json_object_object_add(jobj_digest, "salt", json_object_new_string(digest_desc.salt().c_str()));
290 if (digest_desc.has_digest())
291 json_object_object_add(jobj_digest, "digest", json_object_new_string(digest_desc.digest().c_str()));
292 if (digest_desc.has_hash())
293 json_object_object_add(jobj_digest, "hash", json_object_new_string(hash_algorithm_to_string(digest_desc.hash()).c_str()));
294 if (digest_desc.has_iterations())
295 json_object_object_add(jobj_digest, "iterations", json_object_new_int(digest_desc.iterations()));
297 json_object_object_add(jobj_digests, object_id_to_string(digest_desc.oid()).c_str(), jobj_digest);
300 std::string LUKS2ProtoConverter::segment_type_to_string(segment_type type) {
302 case SEGMENT_TYPE_LINEAR:
304 case SEGMENT_TYPE_CRYPT:
309 std::string LUKS2ProtoConverter::segment_flag_to_string(segment_flag flag) {
311 case IN_REENCRYPTION:
312 return "in-reencryption";
314 return "backup-final";
315 case BACKUP_PREVIOUS:
316 return "backup-previous";
317 case BACKUP_MOVED_SEGMENT:
318 return "backup-moved-segment";
322 void LUKS2ProtoConverter::generate_segment_integrity(struct json_object *jobj_integrity, const segment_integrity_description &segment_integrity_desc) {
323 if (segment_integrity_desc.has_type())
324 json_object_object_add(jobj_integrity, "type", json_object_new_string(segment_integrity_desc.type().c_str()));
325 if (segment_integrity_desc.has_journal_encryption())
326 json_object_object_add(jobj_integrity, "journal_encryption", json_object_new_string(segment_integrity_desc.journal_encryption().c_str()));
327 if (segment_integrity_desc.has_journal_integrity())
328 json_object_object_add(jobj_integrity, "journal_integrity", json_object_new_string(segment_integrity_desc.journal_integrity().c_str()));
331 void LUKS2ProtoConverter::generate_segment(struct json_object *jobj_segments, const segment_description &segment_desc) {
332 json_object *jobj_flags, *jobj_integrity;
333 json_object *jobj_segment = json_object_new_object();
335 if (segment_desc.has_type())
336 json_object_object_add(jobj_segment, "type", json_object_new_string(segment_type_to_string(segment_desc.type()).c_str()));
338 if (segment_desc.has_offset())
339 json_object_object_add(jobj_segment, "offset", json_object_new_string(string_uint64_to_string(segment_desc.offset()).c_str()));
340 if (segment_desc.has_size())
341 json_object_object_add(jobj_segment, "size", json_object_new_string(string_uint64_to_string(segment_desc.size()).c_str()));
343 if (!segment_desc.flags().empty()) {
344 jobj_flags = json_object_new_array();
346 for (const int flag : segment_desc.flags()) {
347 json_object_array_add(jobj_flags,
348 json_object_new_string(segment_flag_to_string(segment_flag(flag)).c_str()));
351 /* Replace or add new flags array */
352 json_object_object_add(jobj_segment, "flags", jobj_flags);
355 if (segment_desc.has_iv_tweak())
356 json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string(string_uint64_to_string(segment_desc.iv_tweak()).c_str()));
357 if (segment_desc.has_encryption())
358 json_object_object_add(jobj_segment, "encryption", json_object_new_string(segment_desc.encryption().c_str()));
359 if (segment_desc.has_sector_size())
360 json_object_object_add(jobj_segment, "sector_size", json_object_new_int(segment_desc.sector_size()));
362 if (segment_desc.has_integrity()) {
363 jobj_integrity = json_object_new_object();
364 generate_segment_integrity(jobj_integrity, segment_desc.integrity());
365 json_object_object_add(jobj_segment, "integrity", jobj_integrity);
368 json_object_object_add(jobj_segments, object_id_to_string(segment_desc.oid()).c_str(), jobj_segment);
371 void LUKS2ProtoConverter::create_jobj(const LUKS2_both_headers &headers) {
372 json_object *jobj_keyslots = NULL;
373 json_object *jobj_digests = NULL;
374 json_object *jobj_segments = NULL;
375 json_object *jobj_tokens = NULL;
377 const json_area_description &json_desc = headers.json_area();
379 jobj = json_object_new_object();
383 jobj_keyslots = json_object_new_object();
384 for (const keyslot_description &keyslot_desc : json_desc.keyslots()) {
385 generate_keyslot(jobj_keyslots, keyslot_desc);
387 json_object_object_add(jobj, "keyslots", jobj_keyslots);
389 jobj_digests = json_object_new_object();
390 for (const digest_description &digest_desc : json_desc.digests()) {
391 generate_digest(jobj_digests, digest_desc);
393 json_object_object_add(jobj, "digests", jobj_digests);
395 jobj_segments = json_object_new_object();
396 for (const segment_description &segment_desc : json_desc.segments()) {
397 generate_segment(jobj_segments, segment_desc);
399 json_object_object_add(jobj, "segments", jobj_segments);
401 jobj_tokens = json_object_new_object();
402 for (const token_description &token_desc : json_desc.tokens()) {
403 generate_token(jobj_tokens, token_desc);
405 json_object_object_add(jobj, "tokens", jobj_tokens);
407 if (json_desc.has_config()) {
408 uint64_t hdr_size = json_desc.config().use_primary_hdr_size() ? headers.primary_header().hdr_size() : headers.secondary_header().hdr_size();
409 generate_config(json_desc.config(), hdr_size - LUKS2_HDR_BIN_LEN, KEYSLOTS_SIZE);
413 void LUKS2ProtoConverter::emit_luks2_binary_header(const LUKS2_header &header_proto, int fd, uint64_t offset, uint64_t seqid) {
414 struct luks2_hdr_disk hdr = {};
418 crypt_hash_destroy(hd);
419 if (crypt_hash_init(&hd, "sha256"))
420 err(EXIT_FAILURE, "crypt_hash_init failed");
423 r = lseek(fd, offset, SEEK_SET);
425 err(EXIT_FAILURE, "lseek failed");
427 switch (header_proto.magic()) {
429 memset(&hdr.magic, 0, LUKS2_MAGIC_L);
432 memcpy(&hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L);
435 memcpy(&hdr.magic, LUKS2_MAGIC_2ND, LUKS2_MAGIC_L);
438 hdr.version = cpu_to_be16(header_proto.version());
439 hdr.hdr_size = cpu_to_be64(header_proto.hdr_size());
440 hdr.seqid = cpu_to_be64(seqid);
441 strncpy(hdr.checksum_alg, "sha256", LUKS2_CHECKSUM_ALG_L);
442 hdr.checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0';
443 strncpy(hdr.uuid, "af7f64ea-3233-4581-946b-6187d812841e", LUKS2_UUID_L);
444 memset(hdr.salt, 1, LUKS2_SALT_L);
447 if (header_proto.has_selected_offset())
448 hdr.hdr_offset = cpu_to_be64(header_proto.selected_offset());
450 hdr.hdr_offset = cpu_to_be64(offset);
452 if (write_buffer(fd, &hdr, LUKS2_HDR_BIN_LEN) != LUKS2_HDR_BIN_LEN)
453 err(EXIT_FAILURE, "write_buffer failed");
454 if (crypt_hash_write(hd, (char*)&hdr, LUKS2_HDR_BIN_LEN))
455 err(EXIT_FAILURE, "crypt_hash_write failed");
457 size_t hdr_json_area_len = header_proto.hdr_size() - LUKS2_HDR_BIN_LEN;
458 size_t json_text_len;
459 const char *json_text;
460 uint8_t csum[LUKS2_CHECKSUM_L];
463 json_text = json_object_to_json_string_ext((struct json_object *)jobj, JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
464 if (!json_text || !*json_text)
465 err(EXIT_FAILURE, "json_object_to_json_string_ext failed");
467 json_text_len = strlen(json_text);
469 size_t write_size = json_text_len > hdr_json_area_len - 1 ? hdr_json_area_len - 1 : json_text_len;
470 if (write_buffer(fd, json_text, write_size) != (ssize_t)write_size)
471 err(EXIT_FAILURE, "write_buffer failed");
472 if (crypt_hash_write(hd, json_text, write_size))
473 err(EXIT_FAILURE, "crypt_hash_write failed");
475 for (size_t i = 0; i < (hdr_json_area_len - write_size); i++) {
476 if (crypt_hash_write(hd, "\0", 1))
477 err(EXIT_FAILURE, "crypt_hash_write failed");
481 if (header_proto.use_correct_checksum()) {
482 if (lseek(fd, offset + offsetof(luks2_hdr_disk, csum), SEEK_SET) == -1)
483 err(EXIT_FAILURE, "lseek failed");
485 int hash_size = crypt_hash_size("sha256");
487 err(EXIT_FAILURE, "crypt_hash_size failed");
489 if (crypt_hash_final(hd, (char*)csum, (size_t)hash_size))
490 err(EXIT_FAILURE, "crypt_hash_final failed");
491 if (write_buffer(fd, csum, hash_size) != hash_size)
492 err(EXIT_FAILURE, "write_buffer failed");
496 void LUKS2ProtoConverter::set_write_headers_only(bool headers_only) {
497 write_headers_only = headers_only;
500 void LUKS2ProtoConverter::convert(const LUKS2_both_headers &headers, int fd) {
501 uint64_t primary_seqid, secondary_seqid;
504 size_t out_size = headers.primary_header().hdr_size() + headers.secondary_header().hdr_size();
506 if (!write_headers_only)
507 out_size += KEYSLOTS_SIZE + DATA_SIZE;
509 result = ftruncate(fd, out_size);
511 err(EXIT_FAILURE, "truncate failed");
513 result = lseek(fd, 0, SEEK_SET);
515 err(EXIT_FAILURE, "lseek failed");
517 switch (headers.seqid()) {
522 case PRIMARY_GREATER:
526 case SECONDARY_GREATER:
532 create_jobj(headers);
533 emit_luks2_binary_header(headers.primary_header(), fd, 0, primary_seqid);
534 emit_luks2_binary_header(headers.secondary_header(), fd, headers.primary_header().hdr_size(), secondary_seqid);
537 std::string LUKS2ProtoConverter::config_flag_to_string(config_flag flag) {
539 case CONFIG_FLAG_ALLOW_DISCARDS:
540 return "allow-discards";
541 case CONFIG_FLAG_SAME_CPU_CRYPT:
542 return "same-cpu-crypt";
543 case CONFIG_FLAG_SUBMIT_FROM_CRYPT_CPUS:
544 return "submit-from-crypt-cpus";
545 case CONFIG_FLAG_NO_JOURNAL:
547 case CONFIG_FLAG_NO_READ_WORKQUEUE:
548 return "no-read-workqueue";
549 case CONFIG_FLAG_NO_WRITE_WORKQUEUE:
550 return "no-write-workqueue";
554 std::string LUKS2ProtoConverter::config_requirement_to_string(config_requirement requirement) {
555 switch (requirement) {
556 case CONFIG_REQUIREMENT_OFFLINE_REENCRYPT:
557 return "offline-reencrypt";
558 case CONFIG_REQUIREMENT_ONLINE_REENCRYPT_V2:
559 return "online-reencrypt-v2";
563 void LUKS2ProtoConverter::generate_config(const config_description &config_desc, uint64_t json_size, uint64_t keyslots_size) {
564 json_object *jobj_config, *jobj_flags, *jobj_requirements, *jobj_mandatory;
565 jobj_config = json_object_new_object();
567 json_object_object_add(jobj_config, "json_size", json_object_new_string(std::to_string(json_size).c_str()));
568 json_object_object_add(jobj_config, "keyslots_size", json_object_new_string(std::to_string(keyslots_size).c_str()));
570 if (!config_desc.config_flags().empty()) {
571 jobj_flags = json_object_new_array();
573 for (const int flag : config_desc.config_flags()) {
574 json_object_array_add(jobj_flags,
575 json_object_new_string(config_flag_to_string(config_flag(flag)).c_str()));
578 /* Replace or add new flags array */
579 json_object_object_add(jobj_config, "flags", jobj_flags);
582 if (!config_desc.requirements().empty()) {
583 jobj_requirements = json_object_new_object();
584 jobj_mandatory = json_object_new_array();
586 for (const int requirement : config_desc.requirements()) {
587 json_object_array_add(jobj_mandatory,
588 json_object_new_string(config_requirement_to_string(config_requirement(requirement)).c_str()));
591 /* Replace or add new requirements array */
592 json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory);
593 json_object_object_add(jobj_config, "requirements", jobj_requirements);
596 json_object_object_add(jobj, "config", jobj_config);
599 LUKS2ProtoConverter::~LUKS2ProtoConverter() {
600 json_object_put(jobj);
602 crypt_hash_destroy(hd);
604 } // namespace LUKS2_proto