Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / tests / fuzz / proto_to_luks2_converter.cc
1 /*
2  * cryptsetup LUKS2 custom mutator fuzz target
3  *
4  * Copyright (C) 2022-2023 Daniel Zatovic <daniel.zatovic@gmail.com>
5  * Copyright (C) 2022-2023 Red Hat, Inc. All rights reserved.
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include "proto_to_luks2_converter.h"
23 #include <iostream>
24
25 extern "C" {
26 #include "src/cryptsetup.h"
27 #include "luks2/luks2.h"
28 #include <err.h>
29 }
30
31 namespace LUKS2_proto {
32
33 std::string LUKS2ProtoConverter::string_uint64_to_string(const string_uint64 &str_u64) {
34   std::ostringstream os;
35
36   if (str_u64.negative())
37     os << "-";
38
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();
43
44   return os.str();
45 }
46
47 std::string LUKS2ProtoConverter::object_id_to_string(const object_id &oid) {
48   std::ostringstream os;
49
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();
54   }
55
56   return os.str();
57 }
58
59 std::string LUKS2ProtoConverter::hash_algorithm_to_string(const hash_algorithm type) {
60   switch (type) {
61     case HASH_ALG_SHA1:
62       return "sha1";
63     case HASH_ALG_SHA256:
64       return "sha256";
65   }
66 }
67
68 std::string LUKS2ProtoConverter::keyslot_area_type_to_string(const keyslot_area_type type) {
69   switch (type) {
70     case KEYSLOT_AREA_TYPE_RAW:
71       return "raw";
72     case KEYSLOT_AREA_TYPE_NONE:
73       return "none";
74     case KEYSLOT_AREA_TYPE_JOURNAL:
75       return "journal";
76     case KEYSLOT_AREA_TYPE_CHECKSUM:
77       return "checksum";
78     case KEYSLOT_AREA_TYPE_DATASHIFT:
79       return "datashift";
80   }
81 }
82
83 void LUKS2ProtoConverter::generate_keyslot_area(struct json_object *jobj_area, const keyslot_area_description &keyslot_area_desc) {
84   // mandatory fields
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()));
91
92   // raw type fields
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()));
97
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()));
103
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()));
107 }
108
109 std::string LUKS2ProtoConverter::keyslot_kdf_type_to_string(const keyslot_kdf_type type) {
110   switch (type) {
111     case KEYSLOT_KDF_TYPE_PBKDF2:
112       return "pbkdf2";
113     case KEYSLOT_KDF_TYPE_ARGON2I:
114       return "argon2i";
115     case KEYSLOT_KDF_TYPE_ARGON2ID:
116       return "argon2id";
117   }
118 }
119
120 void LUKS2ProtoConverter::generate_keyslot_kdf(struct json_object *jobj_kdf, const keyslot_kdf_description &keyslot_kdf_desc) {
121   // mandatory fields
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()));
124
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()));
127   else
128     json_object_object_add(jobj_kdf, "salt", json_object_new_string("6vz4xK7cjan92rDA5JF8O6Jk2HouV0O8DMB6GlztVk="));
129
130   // pbkdf2 type
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()));
135
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()));
143 }
144
145 std::string LUKS2ProtoConverter::keyslot_af_type_to_string(const keyslot_af_type type) {
146   switch (type) {
147     case KEYSLOT_AF_TYPE_LUKS1:
148       return "luks1";
149   }
150 }
151
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()));
159 }
160
161 std::string LUKS2ProtoConverter::keyslot_type_to_string(const keyslot_type type) {
162   switch (type) {
163     case KEYSLOT_TYPE_LUKS2:
164       return "luks2";
165     case KEYSLOT_TYPE_REENCRYPT:
166       return "reencrypt";
167     case KEYSLOT_TYPE_PLACEHOLDER:
168       return "placeholder";
169   }
170 }
171
172 std::string LUKS2ProtoConverter::reencrypt_keyslot_mode_to_string(const reencrypt_keyslot_mode mode) {
173   switch (mode) {
174     case MODE_REENCRYPT:
175       return "reencrypt";
176     case MODE_ENCRYPT:
177       return "encrypt";
178     case MODE_DECRYPT:
179       return "decrypt";
180   }
181 }
182
183 std::string LUKS2ProtoConverter::reencrypt_keyslot_direction_to_string(const reencrypt_keyslot_direction direction) {
184   switch (direction) {
185     case DIRECTION_FORWARD:
186       return "forward";
187     case DIRECTION_BACKWARD:
188       return "backward";
189   }
190 }
191
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;
194
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()));
206
207   /* Area object */
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);
212   }
213
214   /* KDF object */
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);
219   }
220
221   /* AF object */
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);
226   }
227
228   json_object_object_add(jobj_keyslots, object_id_to_string(keyslot_desc.oid()).c_str(), jobj_keyslot);
229 }
230
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();
234
235   if (token_desc.has_type())
236     json_object_object_add(jobj_token, "type", json_object_new_string(token_desc.type().c_str()));
237
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()));
240
241   if (!token_desc.keyslots().empty()) {
242     jobj_keyslots = json_object_new_array();
243
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()));
247     }
248
249     /* Replace or add new keyslots array */
250     json_object_object_add(jobj_token, "keyslots", jobj_keyslots);
251   }
252
253   json_object_object_add(jobj_tokens, object_id_to_string(token_desc.oid()).c_str(), jobj_token);
254 }
255
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;
258
259   jobj_digest = json_object_new_object();
260
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()));
263
264   if (!digest_desc.keyslots().empty()) {
265     jobj_keyslots = json_object_new_array();
266
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()));
270     }
271
272     /* Replace or add new keyslots array */
273     json_object_object_add(jobj_digest, "keyslots", jobj_keyslots);
274   }
275
276   if (!digest_desc.segments().empty()) {
277     jobj_segments = json_object_new_array();
278
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()));
282     }
283
284     /* Replace or add new segments array */
285     json_object_object_add(jobj_digest, "segments", jobj_segments);
286   }
287
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()));
296
297   json_object_object_add(jobj_digests, object_id_to_string(digest_desc.oid()).c_str(), jobj_digest);
298 }
299
300 std::string LUKS2ProtoConverter::segment_type_to_string(segment_type type) {
301   switch (type) {
302     case SEGMENT_TYPE_LINEAR:
303       return "linear";
304     case SEGMENT_TYPE_CRYPT:
305       return "crypt";
306   }
307 }
308
309 std::string LUKS2ProtoConverter::segment_flag_to_string(segment_flag flag) {
310   switch (flag) {
311     case IN_REENCRYPTION:
312       return "in-reencryption";
313     case BACKUP_FINAL:
314       return "backup-final";
315     case BACKUP_PREVIOUS:
316       return "backup-previous";
317     case BACKUP_MOVED_SEGMENT:
318       return "backup-moved-segment";
319   }
320 }
321
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()));
329 }
330
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();
334
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()));
337
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()));
342
343   if (!segment_desc.flags().empty()) {
344     jobj_flags = json_object_new_array();
345
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()));
349     }
350
351     /* Replace or add new flags array */
352     json_object_object_add(jobj_segment, "flags", jobj_flags);
353   }
354
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()));
361
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);
366   }
367
368   json_object_object_add(jobj_segments, object_id_to_string(segment_desc.oid()).c_str(), jobj_segment);
369 }
370
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;
376
377   const json_area_description &json_desc = headers.json_area();
378
379   jobj = json_object_new_object();
380   if (!jobj)
381     return;
382
383   jobj_keyslots = json_object_new_object();
384   for (const keyslot_description &keyslot_desc : json_desc.keyslots()) {
385     generate_keyslot(jobj_keyslots, keyslot_desc);
386   }
387   json_object_object_add(jobj, "keyslots", jobj_keyslots);
388
389   jobj_digests = json_object_new_object();
390   for (const digest_description &digest_desc : json_desc.digests()) {
391     generate_digest(jobj_digests, digest_desc);
392   }
393   json_object_object_add(jobj, "digests", jobj_digests);
394
395   jobj_segments = json_object_new_object();
396   for (const segment_description &segment_desc : json_desc.segments()) {
397     generate_segment(jobj_segments, segment_desc);
398   }
399   json_object_object_add(jobj, "segments", jobj_segments);
400
401   jobj_tokens = json_object_new_object();
402   for (const token_description &token_desc : json_desc.tokens()) {
403     generate_token(jobj_tokens, token_desc);
404   }
405   json_object_object_add(jobj, "tokens", jobj_tokens);
406
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);
410   }
411 }
412
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 = {};
415   int r;
416
417   if (hd)
418     crypt_hash_destroy(hd);
419   if (crypt_hash_init(&hd, "sha256"))
420     err(EXIT_FAILURE, "crypt_hash_init failed");
421
422
423   r = lseek(fd, offset, SEEK_SET);
424   if (r == -1)
425     err(EXIT_FAILURE, "lseek failed");
426
427   switch (header_proto.magic()) {
428     case INVALID:
429       memset(&hdr.magic, 0, LUKS2_MAGIC_L);
430       break;
431     case FIRST:
432       memcpy(&hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L);
433       break;
434     case SECOND:
435       memcpy(&hdr.magic, LUKS2_MAGIC_2ND, LUKS2_MAGIC_L);
436       break;
437   }
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);
445
446
447   if (header_proto.has_selected_offset())
448     hdr.hdr_offset  = cpu_to_be64(header_proto.selected_offset());
449   else
450     hdr.hdr_offset  = cpu_to_be64(offset);
451
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");
456
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];
461
462   if (jobj) {
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");
466
467     json_text_len = strlen(json_text);
468
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");
474
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");
478     }
479   }
480
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");
484
485     int hash_size = crypt_hash_size("sha256");
486     if (hash_size <= 0)
487       err(EXIT_FAILURE, "crypt_hash_size failed");
488
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");
493   }
494 }
495
496 void LUKS2ProtoConverter::set_write_headers_only(bool headers_only) {
497   write_headers_only = headers_only;
498 }
499
500 void LUKS2ProtoConverter::convert(const LUKS2_both_headers &headers, int fd) {
501   uint64_t primary_seqid, secondary_seqid;
502   int result;
503
504   size_t out_size = headers.primary_header().hdr_size() + headers.secondary_header().hdr_size();
505
506   if (!write_headers_only)
507     out_size += KEYSLOTS_SIZE + DATA_SIZE;
508
509   result = ftruncate(fd, out_size);
510   if (result == -1)
511     err(EXIT_FAILURE, "truncate failed");
512
513   result = lseek(fd, 0, SEEK_SET);
514   if (result == -1)
515     err(EXIT_FAILURE, "lseek failed");
516
517   switch (headers.seqid()) {
518     case EQUAL:
519       primary_seqid = 1;
520       secondary_seqid = 1;
521       break;
522     case PRIMARY_GREATER:
523       primary_seqid = 2;
524       secondary_seqid = 1;
525       break;
526     case SECONDARY_GREATER:
527       primary_seqid = 1;
528       secondary_seqid = 2;
529       break;
530   }
531
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);
535 }
536
537 std::string LUKS2ProtoConverter::config_flag_to_string(config_flag flag) {
538   switch (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:
546       return "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";
551   }
552 }
553
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";
560   }
561 }
562
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();
566
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()));
569
570   if (!config_desc.config_flags().empty()) {
571     jobj_flags = json_object_new_array();
572
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()));
576     }
577
578     /* Replace or add new flags array */
579     json_object_object_add(jobj_config, "flags", jobj_flags);
580   }
581
582   if (!config_desc.requirements().empty()) {
583     jobj_requirements = json_object_new_object();
584     jobj_mandatory = json_object_new_array();
585
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()));
589     }
590
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);
594   }
595
596   json_object_object_add(jobj, "config", jobj_config);
597 }
598
599 LUKS2ProtoConverter::~LUKS2ProtoConverter() {
600   json_object_put(jobj);
601   if (hd)
602     crypt_hash_destroy(hd);
603 }
604 }  // namespace LUKS2_proto