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