]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/recovery-key.c
Simplify random number selection
[thirdparty/systemd.git] / src / basic / recovery-key.c
CommitLineData
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
7const char modhex_alphabet[16] = {
8 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v'
9};
10
11int 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
21int 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
74int 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}