cmd_privkey.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. *******************************************************************************
  3. \file cmd_privkey.c
  4. \brief Command-line interface to Bee2: managing private keys
  5. \project bee2/cmd
  6. \created 2022.06.20
  7. \version 2023.06.18
  8. \copyright The Bee2 authors
  9. \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
  10. *******************************************************************************
  11. */
  12. #include "../cmd.h"
  13. #include <bee2/core/blob.h>
  14. #include <bee2/core/dec.h>
  15. #include <bee2/core/err.h>
  16. #include <bee2/core/hex.h>
  17. #include <bee2/core/mem.h>
  18. #include <bee2/core/rng.h>
  19. #include <bee2/core/str.h>
  20. #include <bee2/core/util.h>
  21. #include <bee2/crypto/bign.h>
  22. #include <bee2/crypto/bpki.h>
  23. #include <stdio.h>
  24. /*
  25. *******************************************************************************
  26. Запись личного ключа
  27. *******************************************************************************
  28. */
  29. err_t cmdPrivkeyWrite(const octet privkey[], size_t privkey_len,
  30. const char* file, const cmd_pwd_t pwd)
  31. {
  32. err_t code;
  33. const size_t iter = 10000;
  34. void* stack;
  35. octet* salt;
  36. octet* epki;
  37. size_t epki_len;
  38. FILE* fp;
  39. // pre
  40. ASSERT(privkey_len == 24 || privkey_len == 32 || privkey_len == 48 ||
  41. privkey_len == 64);
  42. ASSERT(memIsValid(privkey, privkey_len));
  43. ASSERT(strIsValid(file));
  44. ASSERT(cmdPwdIsValid(pwd));
  45. // входной контроль
  46. if (!rngIsValid())
  47. return ERR_BAD_RNG;
  48. // определить длину контейнера
  49. code = bpkiPrivkeyWrap(0, &epki_len, 0, privkey_len, 0, 0, 0, iter);
  50. ERR_CALL_CHECK(code);
  51. // выделить память и разметить ее
  52. code = cmdBlobCreate(stack, 8 + epki_len);
  53. ERR_CALL_CHECK(code);
  54. salt = (octet*)stack;
  55. epki = salt + 8;
  56. // установить защиту
  57. rngStepR(salt, 8, 0);
  58. code = bpkiPrivkeyWrap(epki, 0, privkey, privkey_len, (const octet*)pwd,
  59. cmdPwdLen(pwd), salt, iter);
  60. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  61. // открыть файл для записи
  62. fp = fopen(file, "wb");
  63. code = fp ? ERR_OK : ERR_FILE_CREATE;
  64. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  65. // записать
  66. code = fwrite(epki, 1, epki_len, fp) == epki_len ? ERR_OK : ERR_FILE_WRITE;
  67. fclose(fp);
  68. // завершить
  69. cmdBlobClose(stack);
  70. return code;
  71. }
  72. /*
  73. *******************************************************************************
  74. Чтение личного ключа
  75. *******************************************************************************
  76. */
  77. err_t cmdPrivkeyRead(octet privkey[], size_t* privkey_len, const char* file,
  78. const cmd_pwd_t pwd)
  79. {
  80. err_t code;
  81. size_t len;
  82. size_t epki_len;
  83. size_t epki_len_min;
  84. size_t epki_len_max;
  85. void* stack;
  86. octet* epki;
  87. FILE* fp;
  88. // pre
  89. ASSERT(memIsNullOrValid(privkey_len, sizeof(size_t)));
  90. ASSERT(!privkey_len || *privkey_len == 0 || *privkey_len == 24 ||
  91. *privkey_len == 32 || *privkey_len == 48 || *privkey_len == 64);
  92. ASSERT(strIsValid(file));
  93. ASSERT(cmdPwdIsValid(pwd));
  94. // определить длину личного ключа по размеру контейнера
  95. if (!privkey_len || *privkey_len == 0)
  96. {
  97. // определить размер контейнера
  98. if ((epki_len = cmdFileSize(file)) == SIZE_MAX)
  99. return ERR_FILE_READ;
  100. // найти подходящую длину
  101. for (len = 24; len <= 64; len = len == 24 ? len + 8 : len + 16)
  102. {
  103. code = bpkiPrivkeyWrap(0, &epki_len_min, 0, len, 0, 0, 0, 10000);
  104. ERR_CALL_CHECK(code);
  105. code = bpkiPrivkeyWrap(0, &epki_len_max, 0, len, 0, 0, 0, SIZE_MAX);
  106. ERR_CALL_CHECK(code);
  107. if (epki_len_min <= epki_len && epki_len <= epki_len_max)
  108. break;
  109. }
  110. if (len > 64)
  111. return ERR_BAD_FORMAT;
  112. if (privkey_len)
  113. *privkey_len = len;
  114. }
  115. // обработать переданную длину личного ключа
  116. else
  117. {
  118. len = *privkey_len;
  119. code = bpkiPrivkeyWrap(0, &epki_len_min, 0, len, 0, 0, 0, 10000);
  120. ERR_CALL_CHECK(code);
  121. code = bpkiPrivkeyWrap(0, &epki_len_max, 0, len, 0, 0, 0, SIZE_MAX);
  122. ERR_CALL_CHECK(code);
  123. }
  124. // ключ определять не нужно?
  125. if (!privkey)
  126. return ERR_OK;
  127. ASSERT(len == 24 || len == 32 || len == 48 || len == 64);
  128. ASSERT(memIsValid(privkey, len));
  129. // выделить память и разметить ее
  130. code = cmdBlobCreate(stack, epki_len_max + 1);
  131. ERR_CALL_CHECK(code);
  132. epki = (octet*)stack;
  133. // прочитать контейнер
  134. code = (fp = fopen(file, "rb")) ? ERR_OK : ERR_FILE_OPEN;
  135. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  136. epki_len = fread(epki, 1, epki_len_max + 1, fp);
  137. fclose(fp);
  138. code = (epki_len_min <= epki_len && epki_len <= epki_len_max) ?
  139. ERR_OK : ERR_BAD_FORMAT;
  140. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  141. // снять защиту
  142. code = bpkiPrivkeyUnwrap(privkey, &epki_len_min, epki, epki_len,
  143. (const octet*)pwd, cmdPwdLen(pwd));
  144. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  145. ASSERT(epki_len_min == len);
  146. cmdBlobClose(stack);
  147. return code;
  148. }