/* SPDX-License-Identifier: LGPL-2.1+ */

#include <errno.h>

#include "modhex.h"
#include "macro.h"
#include "memory-util.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,
                    MODHEX_RAW_LENGTH*2,          /* syntax without dashes */
                    MODHEX_FORMATTED_LENGTH-1))   /* syntax with dashes */
                return -EINVAL;

        mangled = new(char, MODHEX_FORMATTED_LENGTH);
        if (!mangled)
                return -ENOMEM;

        for (size_t i = 0, j = 0; i < MODHEX_RAW_LENGTH; i++) {
                size_t k;
                int a, b;

                if (l == MODHEX_RAW_LENGTH*2)
                        /* Syntax without dashes */
                        k = i * 2;
                else {
                        /* Syntax with dashes */
                        assert(l == 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[MODHEX_FORMATTED_LENGTH-1] = 0;

        *ret = TAKE_PTR(mangled);
        return 0;
}
