1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "memory-util.h"
4 #include "random-util.h"
5 #include "recovery-key.h"
6
7 const char modhex_alphabet[16] = {
8 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v'
9 };
10
decode_modhex_char(char x)11 int decode_modhex_char(char x) {
12
13 for (size_t i = 0; i < ELEMENTSOF(modhex_alphabet); i++)
14 /* Check both upper and lowercase */
15 if (modhex_alphabet[i] == x || (modhex_alphabet[i] - 32) == x)
16 return i;
17
18 return -EINVAL;
19 }
20
normalize_recovery_key(const char * password,char ** ret)21 int normalize_recovery_key(const char *password, char **ret) {
22 _cleanup_(erase_and_freep) char *mangled = NULL;
23 size_t l;
24
25 assert(password);
26 assert(ret);
27
28 l = strlen(password);
29 if (!IN_SET(l,
30 RECOVERY_KEY_MODHEX_RAW_LENGTH*2, /* syntax without dashes */
31 RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1)) /* syntax with dashes */
32 return -EINVAL;
33
34 mangled = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH);
35 if (!mangled)
36 return -ENOMEM;
37
38 for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) {
39 size_t k;
40 int a, b;
41
42 if (l == RECOVERY_KEY_MODHEX_RAW_LENGTH*2)
43 /* Syntax without dashes */
44 k = i * 2;
45 else {
46 /* Syntax with dashes */
47 assert(l == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1);
48 k = i * 2 + i / 4;
49
50 if (i > 0 && i % 4 == 0 && password[k-1] != '-')
51 return -EINVAL;
52 }
53
54 a = decode_modhex_char(password[k]);
55 if (a < 0)
56 return -EINVAL;
57 b = decode_modhex_char(password[k+1]);
58 if (b < 0)
59 return -EINVAL;
60
61 mangled[j++] = modhex_alphabet[a];
62 mangled[j++] = modhex_alphabet[b];
63
64 if (i % 4 == 3)
65 mangled[j++] = '-';
66 }
67
68 mangled[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0;
69
70 *ret = TAKE_PTR(mangled);
71 return 0;
72 }
73
make_recovery_key(char ** ret)74 int make_recovery_key(char **ret) {
75 _cleanup_(erase_and_freep) char *formatted = NULL;
76 _cleanup_(erase_and_freep) uint8_t *key = NULL;
77 size_t j = 0;
78 int r;
79
80 assert(ret);
81
82 key = new(uint8_t, RECOVERY_KEY_MODHEX_RAW_LENGTH);
83 if (!key)
84 return -ENOMEM;
85
86 r = genuine_random_bytes(key, RECOVERY_KEY_MODHEX_RAW_LENGTH, RANDOM_BLOCK);
87 if (r < 0)
88 return r;
89
90 /* Let's now format it as 64 modhex chars, and after each 8 chars insert a dash */
91 formatted = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH);
92 if (!formatted)
93 return -ENOMEM;
94
95 for (size_t i = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) {
96 formatted[j++] = modhex_alphabet[key[i] >> 4];
97 formatted[j++] = modhex_alphabet[key[i] & 0xF];
98
99 if (i % 4 == 3)
100 formatted[j++] = '-';
101 }
102
103 assert(j == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH);
104 assert(formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] == '-');
105 formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; /* replace final dash with a NUL */
106
107 *ret = TAKE_PTR(formatted);
108 return 0;
109 }
110