123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- /*
- *******************************************************************************
- \file cmd_pwd.c
- \brief Command-line interface to Bee2: password management
- \project bee2/cmd
- \created 2022.06.13
- \version 2025.05.07
- \copyright The Bee2 authors
- \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
- *******************************************************************************
- */
- #include <stdlib.h>
- #include <bee2/core/blob.h>
- #include <bee2/core/dec.h>
- #include <bee2/core/err.h>
- #include <bee2/core/hex.h>
- #include <bee2/core/mem.h>
- #include <bee2/core/rng.h>
- #include <bee2/core/str.h>
- #include <bee2/core/util.h>
- #include <bee2/crypto/belt.h>
- #include <bee2/crypto/bels.h>
- #include <bee2/crypto/bpki.h>
- #include "../cmd.h"
- /*
- *******************************************************************************
- Управление паролями: базовые функции
- *******************************************************************************
- */
- cmd_pwd_t cmdPwdCreate(size_t size)
- {
- return (cmd_pwd_t)blobCreate(size + 1);
- }
- bool_t cmdPwdIsValid(const cmd_pwd_t pwd)
- {
- return strIsValid(pwd) && blobIsValid(pwd) &&
- pwd[blobSize(pwd) - 1] == '\0';
- }
- void cmdPwdClose(cmd_pwd_t pwd)
- {
- ASSERT(pwd == 0 || cmdPwdIsValid(pwd));
- blobClose(pwd);
- }
- /*
- *******************************************************************************
- Управление паролями: схема pass
- *******************************************************************************
- */
- static err_t cmdPwdGenPass(cmd_pwd_t* pwd, const char* str)
- {
- return ERR_NOT_IMPLEMENTED;
- }
- static err_t cmdPwdReadPass(cmd_pwd_t* pwd, const char* str)
- {
- ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t)));
- ASSERT(strIsValid(str));
- // создать пароль
- if (!(*pwd = cmdPwdCreate(strLen(str))))
- return ERR_OUTOFMEMORY;
- strCopy(*pwd, str);
- return ERR_OK;
- }
- /*
- *******************************************************************************
- Управление паролями: схема env
- *******************************************************************************
- */
- static const char* cmdEnvGet(const char* name)
- {
- const char* val;
- val = getenv(name);
- return strIsValid(val) ? val : 0;
- }
- static err_t cmdPwdGenEnv(cmd_pwd_t* pwd, const char* str)
- {
- return ERR_NOT_IMPLEMENTED;
- }
- static err_t cmdPwdReadEnv(cmd_pwd_t* pwd, const char* str)
- {
- const char* val;
- // pre
- ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t)));
- ASSERT(strIsValid(str));
- // читать пароль из переменной окружения
- if (!(val = cmdEnvGet(str)))
- return ERR_BAD_ENV;
- // возвратить пароль
- if (!(*pwd = cmdPwdCreate(strLen(val))))
- return ERR_OUTOFMEMORY;
- strCopy(*pwd, val);
- return ERR_OK;
- }
- /*
- *******************************************************************************
- Управление паролями: схема share
- *******************************************************************************
- */
- static err_t cmdPwdGenShare_internal(cmd_pwd_t* pwd, size_t scount,
- size_t threshold, size_t len, bool_t crc, char* shares[],
- const cmd_pwd_t spwd)
- {
- err_t code;
- const size_t iter = 10000;
- size_t epki_len;
- void* stack;
- octet* pwd_bin;
- octet* state;
- octet* share;
- octet* salt;
- octet* epki;
- // pre
- ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t)));
- ASSERT(cmdPwdIsValid(spwd));
- ASSERT(2 <= scount && scount <= 16);
- ASSERT(2 <= threshold && threshold <= scount);
- ASSERT(len % 8 == 0 && len <= 32);
- ASSERT(!crc || len != 16);
- // пароль пока не создан
- *pwd = 0;
- // определить длину пароля
- if (len == 0)
- len = 32;
- // определить длину контейнера с частичным секретом
- code = bpkiShareWrap(0, &epki_len, 0, len + 1, 0, 0, 0, iter);
- ERR_CALL_CHECK(code);
- // запустить ГСЧ
- code = cmdRngStart(TRUE);
- ERR_CALL_CHECK(code);
- // выделить память и разметить ее
- code = cmdBlobCreate(stack, len +
- utilMax(2,
- beltMAC_keep(),
- scount * (len + 1) + epki_len + 8));
- ERR_CALL_CHECK(code);
- pwd_bin = (octet*)stack;
- state = share = pwd_bin + len;
- salt = share + scount * (len + 1);
- epki = salt + 8;
- // генерировать пароль
- if (crc)
- {
- rngStepR(pwd_bin, len - 8, 0);
- beltMACStart(state, pwd_bin, len - 8);
- beltMACStepA(pwd_bin, len - 8, state);
- beltMACStepG(pwd_bin + len - 8, state);
- }
- else
- rngStepR(pwd_bin, len, 0);
- // разделить пароль на частичные секреты
- code = belsShare2(share, scount, threshold, len, pwd_bin, rngStepR, 0);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // обновить ключ ГСЧ
- rngRekey();
- // защитить частичные секреты
- for (; scount--; share += (len + 1), ++shares)
- {
- // установить защиту
- rngStepR(salt, 8, 0);
- code = bpkiShareWrap(epki, 0, share, len + 1, (const octet*)spwd,
- cmdPwdLen(spwd), salt, iter);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // записать в файл
- code = cmdFileWrite(*shares, epki, epki_len);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- }
- // создать выходной (текстовый) пароль
- *pwd = cmdPwdCreate(2 * len);
- code = *pwd ? ERR_OK : ERR_OUTOFMEMORY;
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- hexFrom(*pwd, pwd_bin, len);
- cmdBlobClose(stack);
- return code;
- }
- static err_t cmdPwdReadShare_internal(cmd_pwd_t* pwd, size_t scount,
- size_t len, bool_t crc, char* shares[], const cmd_pwd_t spwd)
- {
- err_t code;
- size_t epki_len;
- size_t epki_len_min;
- size_t epki_len_max;
- void* stack;
- octet* share;
- octet* state;
- octet* epki;
- octet* pwd_bin;
- size_t pos;
- // pre
- ASSERT(memIsValid(pwd, sizeof(cmd_pwd_t)));
- ASSERT(cmdPwdIsValid(spwd));
- ASSERT(2 <= scount && scount <= 16);
- ASSERT(len % 8 == 0 && len <= 32);
- ASSERT(!crc || len != 16);
- // пароль пока не создан
- *pwd = 0;
- // определить длину частичного секрета
- if (len == 0)
- {
- // определить размер первого файла с частичным секретом
- if ((epki_len = cmdFileSize(shares[0])) == SIZE_MAX)
- return ERR_FILE_READ;
- // найти подходящую длину
- for (len = 16; len <= 32; len += 8)
- {
- code = bpkiShareWrap(0, &epki_len_min, 0, len + 1, 0, 0, 0, 10000);
- ERR_CALL_CHECK(code);
- code = bpkiShareWrap(0, &epki_len_max, 0, len + 1, 0, 0, 0,
- SIZE_MAX);
- ERR_CALL_CHECK(code);
- if (epki_len_min <= epki_len && epki_len <= epki_len_max)
- break;
- }
- if (len > 32)
- return ERR_BAD_FORMAT;
- }
- else
- {
- code = bpkiShareWrap(0, &epki_len_min, 0, len + 1, 0, 0, 0, 10000);
- ERR_CALL_CHECK(code);
- code = bpkiShareWrap(0, &epki_len_max, 0, len + 1, 0, 0, 0, SIZE_MAX);
- ERR_CALL_CHECK(code);
- }
- // выделить память и разметить ее
- code = cmdBlobCreate(stack, scount * (len + 1) + epki_len_max + 1 + len);
- ERR_CALL_HANDLE(code, cmdPwdClose(*pwd));
- share = state = (octet*)stack;
- epki = share + scount * (len + 1);
- pwd_bin = epki + epki_len_max + 1;
- // прочитать частичные секреты
- for (pos = 0; pos < scount; ++pos, ++shares)
- {
- size_t share_len;
- // определить длину контейнера
- code = cmdFileReadAll(0, &epki_len, *shares);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // проверить длину
- code = (epki_len_min <= epki_len && epki_len <= epki_len_max) ?
- ERR_OK : ERR_BAD_FORMAT;
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // читать
- code = cmdFileReadAll(epki, &epki_len, *shares);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // декодировать
- code = bpkiShareUnwrap(share + pos * (len + 1), &share_len,
- epki, epki_len, (const octet*)spwd, cmdPwdLen(spwd));
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- code = (share_len == len + 1) ? ERR_OK : ERR_BAD_FORMAT;
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- }
- // собрать пароль
- code = belsRecover2(pwd_bin, scount, len, share);
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // проверить пароль
- if (crc)
- {
- beltMACStart(state, pwd_bin, len - 8);
- beltMACStepA(pwd_bin, len - 8, state);
- if (!beltMACStepV(pwd_bin + len - 8, state))
- code = ERR_BAD_CRC;
- }
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- // создать выходной (текстовый) пароль
- *pwd = cmdPwdCreate(2 * len);
- code = *pwd ? ERR_OK : ERR_OUTOFMEMORY;
- ERR_CALL_HANDLE(code, cmdBlobClose(stack));
- hexFrom(*pwd, pwd_bin, len);
- cmdBlobClose(stack);
- return code;
- }
- static err_t cmdPwdGenShare(cmd_pwd_t* pwd, const char* str)
- {
- err_t code;
- int argc;
- char** argv = 0;
- size_t offset = 0;
- size_t threshold = 0;
- size_t len = 0;
- bool_t crc = FALSE;
- cmd_pwd_t spwd = 0;
- // составить список аргументов
- code = cmdArgCreate(&argc, &argv, str);
- ERR_CALL_CHECK(code);
- // обработать опции
- while (argc && strStartsWith(argv[offset], "-"))
- {
- // порог
- if (strStartsWith(argv[offset], "-t"))
- {
- char* dec = argv[offset] + strLen("-t");
- if (threshold)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (!decIsValid(dec) || decCLZ(dec) || strLen(dec) > 2 ||
- (threshold = (size_t)decToU32(dec)) < 2 || threshold > 16)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- ++offset, --argc;
- }
- // уровень стойкости
- else if (strStartsWith(argv[offset], "-l"))
- {
- char* dec = argv[offset] + strLen("-l");
- if (len)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (!decIsValid(dec) || decCLZ(dec) || strLen(dec) != 3 ||
- (len = (size_t)decToU32(dec)) % 64 || len < 128 || len > 256)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- len /= 8;
- if (len == 16 && crc)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- ++offset, --argc;
- }
- // контрольная сумма
- else if (strStartsWith(argv[offset], "-crc"))
- {
- if (crc)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (len == 16)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- crc = TRUE, ++offset, --argc;
- }
- // пароль защиты частичных секретов
- else if (strEq(argv[offset], "-pass"))
- {
- if (spwd)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- ++offset, --argc;
- // определить пароль защиты частичных секретов
- code = cmdPwdRead(&spwd, argv[offset]);
- ERR_CALL_HANDLE(code, cmdArgClose(argv));
- ASSERT(cmdPwdIsValid(spwd));
- ++offset, --argc;
- }
- else
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- }
- // проверить, что пароль защиты частичных секретов построен
- if (!spwd)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- // настроить порог
- if (!threshold)
- threshold = 2;
- // проверить число файлов с частичными секретами
- if ((size_t)argc < threshold)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- // проверить отсутствие файлов с частичными секретами
- if ((code = cmdFileValNotExist(argc, argv + offset)) != ERR_OK)
- goto final;
- // построить пароль
- code = cmdPwdGenShare_internal(pwd, (size_t)argc, threshold, len, crc,
- argv + offset, spwd);
- final:
- cmdPwdClose(spwd);
- cmdArgClose(argv);
- return code;
- }
- static err_t cmdPwdReadShare(cmd_pwd_t* pwd, const char* str)
- {
- err_t code;
- int argc;
- char** argv = 0;
- size_t offset = 0;
- size_t threshold = 0;
- size_t len = 0;
- bool_t crc = FALSE;
- cmd_pwd_t spwd = 0;
- // составить список аргументов
- code = cmdArgCreate(&argc, &argv, str);
- ERR_CALL_CHECK(code);
- // обработать опции
- while (argc && strStartsWith(argv[offset], "-"))
- {
- // порог
- if (strStartsWith(argv[offset], "-t"))
- {
- char* dec = argv[offset] + strLen("-t");
- if (threshold)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (!decIsValid(dec) || decCLZ(dec) || strLen(dec) > 2 ||
- (threshold = (size_t)decToU32(dec)) < 2 || threshold > 16)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- ++offset, --argc;
- }
- // уровень стойкости
- else if (strStartsWith(argv[offset], "-l"))
- {
- char* dec = argv[offset] + strLen("-l");
- if (len)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (!decIsValid(dec) || decCLZ(dec) || strLen(dec) != 3 ||
- (len = (size_t)decToU32(dec)) % 64 || len < 128 || len > 256)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- len /= 8;
- if (len == 16 && crc)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- ++offset, --argc;
- }
- // контрольная сумма
- else if (strStartsWith(argv[offset], "-crc"))
- {
- if (crc)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- if (len == 16)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- crc = TRUE, ++offset, --argc;
- }
- // пароль защиты частичных секретов
- else if (strEq(argv[offset], "-pass"))
- {
- if (spwd)
- {
- code = ERR_CMD_DUPLICATE;
- goto final;
- }
- ++offset, --argc;
- // определить пароль защиты частичных секретов
- code = cmdPwdRead(&spwd, argv[offset]);
- ERR_CALL_HANDLE(code, cmdArgClose(argv));
- ASSERT(cmdPwdIsValid(spwd));
- ++offset, --argc;
- }
- else
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- }
- // проверить, что пароль защиты частичных секретов определен
- if (!spwd)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- // настроить порог
- if (!threshold)
- threshold = 2;
- // проверить число файлов с частичными секретами
- if ((size_t)argc < threshold)
- {
- code = ERR_CMD_PARAMS;
- goto final;
- }
- // проверить наличие файлов с частичными секретами
- if ((code = cmdFileValExist(argc, argv + offset)) != ERR_OK)
- goto final;
- // определить пароль
- code = cmdPwdReadShare_internal(pwd, (size_t)argc, len, crc,
- argv + offset, spwd);
- final:
- cmdPwdClose(spwd);
- cmdArgClose(argv);
- return code;
- }
- /*
- *******************************************************************************
- Управление паролями: построение / определение
- *******************************************************************************
- */
- err_t cmdPwdGen(cmd_pwd_t* pwd, const char* schema)
- {
- if (strStartsWith(schema, "pass:"))
- return cmdPwdGenPass(pwd, schema + strLen("pass:"));
- else if (strStartsWith(schema, "env:"))
- return cmdPwdGenEnv(pwd, schema + strLen("env:"));
- else if (strStartsWith(schema, "share:"))
- return cmdPwdGenShare(pwd, schema + strLen("share:"));
- return ERR_CMD_PARAMS;
- }
- err_t cmdPwdRead(cmd_pwd_t* pwd, const char* schema)
- {
- if (strStartsWith(schema, "pass:"))
- return cmdPwdReadPass(pwd, schema + strLen("pass:"));
- else if (strStartsWith(schema, "env:"))
- return cmdPwdReadEnv(pwd, schema + strLen("env:"));
- else if (strStartsWith(schema, "share:"))
- return cmdPwdReadShare(pwd, schema + strLen("share:"));
- return ERR_CMD_PARAMS;
- }
|