| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #include "memory-util.h" |
| #include "random-util.h" |
| #include "recovery-key.h" |
| |
| const char modhex_alphabet[16] = { |
| 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' |
| }; |
| |
| int decode_modhex_char(char x) { |
| |
| for (size_t i = 0; i < ELEMENTSOF(modhex_alphabet); i++) |
| /* Check both upper and lowercase */ |
| if (modhex_alphabet[i] == x || (modhex_alphabet[i] - 32) == x) |
| return i; |
| |
| return -EINVAL; |
| } |
| |
| int normalize_recovery_key(const char *password, char **ret) { |
| _cleanup_(erase_and_freep) char *mangled = NULL; |
| size_t l; |
| |
| assert(password); |
| assert(ret); |
| |
| l = strlen(password); |
| if (!IN_SET(l, |
| RECOVERY_KEY_MODHEX_RAW_LENGTH*2, /* syntax without dashes */ |
| RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1)) /* syntax with dashes */ |
| return -EINVAL; |
| |
| mangled = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); |
| if (!mangled) |
| return -ENOMEM; |
| |
| for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { |
| size_t k; |
| int a, b; |
| |
| if (l == RECOVERY_KEY_MODHEX_RAW_LENGTH*2) |
| /* Syntax without dashes */ |
| k = i * 2; |
| else { |
| /* Syntax with dashes */ |
| assert(l == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1); |
| k = i * 2 + i / 4; |
| |
| if (i > 0 && i % 4 == 0 && password[k-1] != '-') |
| return -EINVAL; |
| } |
| |
| a = decode_modhex_char(password[k]); |
| if (a < 0) |
| return -EINVAL; |
| b = decode_modhex_char(password[k+1]); |
| if (b < 0) |
| return -EINVAL; |
| |
| mangled[j++] = modhex_alphabet[a]; |
| mangled[j++] = modhex_alphabet[b]; |
| |
| if (i % 4 == 3) |
| mangled[j++] = '-'; |
| } |
| |
| mangled[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; |
| |
| *ret = TAKE_PTR(mangled); |
| return 0; |
| } |
| |
| int make_recovery_key(char **ret) { |
| _cleanup_(erase_and_freep) char *formatted = NULL; |
| _cleanup_(erase_and_freep) uint8_t *key = NULL; |
| size_t j = 0; |
| int r; |
| |
| assert(ret); |
| |
| key = new(uint8_t, RECOVERY_KEY_MODHEX_RAW_LENGTH); |
| if (!key) |
| return -ENOMEM; |
| |
| r = crypto_random_bytes(key, RECOVERY_KEY_MODHEX_RAW_LENGTH); |
| if (r < 0) |
| return r; |
| |
| /* Let's now format it as 64 modhex chars, and after each 8 chars insert a dash */ |
| formatted = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); |
| if (!formatted) |
| return -ENOMEM; |
| |
| for (size_t i = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { |
| formatted[j++] = modhex_alphabet[key[i] >> 4]; |
| formatted[j++] = modhex_alphabet[key[i] & 0xF]; |
| |
| if (i % 4 == 3) |
| formatted[j++] = '-'; |
| } |
| |
| assert(j == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); |
| assert(formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] == '-'); |
| formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; /* replace final dash with a NUL */ |
| |
| *ret = TAKE_PTR(formatted); |
| return 0; |
| } |