]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
aecbc87d | 2 | |
aecbc87d | 3 | #include "memory-util.h" |
73d874ba LP |
4 | #include "random-util.h" |
5 | #include "recovery-key.h" | |
aecbc87d LP |
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 | ||
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 | ||
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, | |
73d874ba LP |
30 | RECOVERY_KEY_MODHEX_RAW_LENGTH*2, /* syntax without dashes */ |
31 | RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1)) /* syntax with dashes */ | |
aecbc87d LP |
32 | return -EINVAL; |
33 | ||
73d874ba | 34 | mangled = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); |
aecbc87d LP |
35 | if (!mangled) |
36 | return -ENOMEM; | |
37 | ||
73d874ba | 38 | for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { |
aecbc87d LP |
39 | size_t k; |
40 | int a, b; | |
41 | ||
73d874ba | 42 | if (l == RECOVERY_KEY_MODHEX_RAW_LENGTH*2) |
aecbc87d LP |
43 | /* Syntax without dashes */ |
44 | k = i * 2; | |
45 | else { | |
46 | /* Syntax with dashes */ | |
73d874ba | 47 | assert(l == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1); |
aecbc87d LP |
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 | ||
73d874ba | 68 | mangled[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; |
aecbc87d LP |
69 | |
70 | *ret = TAKE_PTR(mangled); | |
71 | return 0; | |
72 | } | |
73d874ba LP |
73 | |
74 | int make_recovery_key(char **ret) { | |
75 | _cleanup_(erase_and_freep) char *formatted = NULL; | |
76 | _cleanup_(erase_and_freep) uint8_t *key = NULL; | |
ff2cf6f8 | 77 | size_t j = 0; |
73d874ba LP |
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 | ||
87cb1ab6 | 86 | r = crypto_random_bytes(key, RECOVERY_KEY_MODHEX_RAW_LENGTH); |
73d874ba LP |
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 | ||
ff2cf6f8 | 95 | for (size_t i = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { |
73d874ba LP |
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 | ||
ff2cf6f8 LP |
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 */ | |
73d874ba LP |
106 | |
107 | *ret = TAKE_PTR(formatted); | |
108 | return 0; | |
109 | } |