es.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. *******************************************************************************
  3. \file es.c
  4. \brief Dealing with entropy sources
  5. \project bee2/cmd
  6. \created 2021.04.20
  7. \version 2022.11.04
  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/err.h>
  14. #include <bee2/core/dec.h>
  15. #include <bee2/core/mem.h>
  16. #include <bee2/core/rng.h>
  17. #include <bee2/core/str.h>
  18. #include <bee2/core/mt.h>
  19. #include <bee2/core/tm.h>
  20. #include <bee2/core/util.h>
  21. #include <bee2/core/word.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. /*
  25. *******************************************************************************
  26. Утилита es
  27. Функционал:
  28. - перечень доступных источников энтропии;
  29. - проверка работоспосбности источников энтропии;
  30. - выгрузка данных от стандартных источников энтропии;
  31. - эксперименты с источником timer.
  32. Пример:
  33. bee2cmd es print
  34. bee2cmd es read trng2 128 file
  35. *******************************************************************************
  36. */
  37. static const char _name[] = "es";
  38. static const char _descr[] = "dealing with entropy sources";
  39. static int esUsage()
  40. {
  41. printf(
  42. "bee2cmd/%s: %s\n"
  43. "Usage:\n"
  44. " es print\n"
  45. " list available entropy sources and determine their health\n"
  46. " es read <source> <count> <file>\n"
  47. " read <count> Kbytes from <source> and store them in <file>\n"
  48. " <source> in {trng, trng2, sys, timer, timerNN}\n"
  49. " timerNNN -- use NNN sleep delays to produce one output bit\n",
  50. _name, _descr
  51. );
  52. return -1;
  53. }
  54. /*
  55. *******************************************************************************
  56. Информация об источниках энтропии
  57. print
  58. *******************************************************************************
  59. */
  60. static err_t esPrint(int argc, char* argv[])
  61. {
  62. const char* sources[] = { "trng", "trng2", "sys", "timer" };
  63. size_t pos;
  64. size_t count;
  65. size_t read;
  66. // проверить параметры
  67. if (argc != 0)
  68. return ERR_CMD_PARAMS;
  69. // опрос источников
  70. printf("Sources:");
  71. for (pos = count = 0; pos < COUNT_OF(sources); ++pos)
  72. if (rngESRead(&read, 0, 0, sources[pos]) == ERR_OK)
  73. {
  74. printf(" %s%c", sources[pos],
  75. rngESTest(sources[pos]) == ERR_OK ? '+' : '-');
  76. ++count;
  77. }
  78. printf(count ? "\n" : " none\n");
  79. // общая работоспособность
  80. printf("Health (at least two healthy sources): %c\n",
  81. rngESHealth() == ERR_OK ? '+' : '-');
  82. printf("Health2 (there is a healthy physical source): %c\n",
  83. rngESHealth2() == ERR_OK ? '+' : '-');
  84. printf("\\warning health is volatile\n");
  85. return ERR_OK;
  86. }
  87. /*
  88. *******************************************************************************
  89. Чтение данных
  90. es read <source> <count> <file>
  91. *******************************************************************************
  92. */
  93. static err_t rngReadSourceEx(size_t* read, void* buf, size_t count,
  94. const char* source_name, size_t par)
  95. {
  96. if (strEq(source_name, "trng") || strEq(source_name, "trng2") ||
  97. strEq(source_name, "sys") ||
  98. strEq(source_name, "timer") && par == 0)
  99. return rngESRead(read, buf, count, source_name);
  100. // эксперименты с источником timer
  101. {
  102. register tm_ticks_t ticks;
  103. register tm_ticks_t t;
  104. register word w;
  105. size_t i, j, reps;
  106. // pre
  107. ASSERT(memIsValid(read, sizeof(size_t)));
  108. ASSERT(memIsValid(buf, count));
  109. // генерация
  110. for (i = 0; i < count; ++i)
  111. {
  112. ((octet*)buf)[i] = 0;
  113. ticks = tmTicks();
  114. for (j = 0; j < 8; ++j)
  115. {
  116. w = 0;
  117. for (reps = 0; reps < par; ++reps)
  118. {
  119. mtSleep(0);
  120. t = tmTicks();
  121. w ^= (word)(t - ticks);
  122. ticks = t;
  123. }
  124. ((octet*)buf)[i] ^= wordParity(w) << j;
  125. }
  126. }
  127. ticks = t = 0, w = 0;
  128. *read = count;
  129. return ERR_OK;
  130. }
  131. return ERR_OK;
  132. }
  133. static err_t esRead(int argc, char *argv[])
  134. {
  135. err_t code;
  136. char source[6];
  137. size_t par = 0;
  138. size_t count;
  139. FILE* fp;
  140. octet buf[2048];
  141. // разбор командной строки: число параметров
  142. if (argc != 3)
  143. return ERR_CMD_PARAMS;
  144. // разбор командной строки: источник энтропии
  145. if (strEq(argv[0], "trng"))
  146. strCopy(source, "trng");
  147. else if (strEq(argv[0], "trng2"))
  148. strCopy(source, "trng2");
  149. else if (strEq(argv[0], "sys"))
  150. strCopy(source, "sys");
  151. else if (strEq(argv[0], "timer"))
  152. strCopy(source, "timer");
  153. else if (strStartsWith(argv[0], "timer"))
  154. {
  155. strCopy(source, "timer");
  156. argv[0] += strLen("timer");
  157. if (!decIsValid(argv[0]) || !strLen(argv[0]) ||
  158. strLen(argv[0]) > 3 || decCLZ(argv[0]))
  159. return ERR_CMD_PARAMS;
  160. par = (size_t)decToU32(argv[0]);
  161. }
  162. else
  163. return ERR_CMD_PARAMS;
  164. // разбор командной строки: число Кбайтов
  165. if (!decIsValid(argv[1]) || !strLen(argv[1]) ||
  166. strLen(argv[1]) > 4 || decCLZ(argv[1]))
  167. return ERR_CMD_PARAMS;
  168. count = (size_t)decToU32(argv[1]);
  169. if (((count << 10) >> 10) != count)
  170. return ERR_OUTOFRANGE;
  171. count <<= 10;
  172. // разбор командной строки: имя выходного файла
  173. code = cmdFileValNotExist(1, argv + 2);
  174. ERR_CALL_CHECK(code);
  175. fp = fopen(argv[2], "wb");
  176. if (!fp)
  177. return ERR_FILE_OPEN;
  178. // выгрузка данных
  179. while (count)
  180. {
  181. size_t read;
  182. // читать
  183. code = rngReadSourceEx(&read, buf,
  184. MIN2(sizeof(buf), count), source, par);
  185. ERR_CALL_HANDLE(code, fclose(fp));
  186. code = read == MIN2(sizeof(buf), count) ? ERR_OK : ERR_FILE_READ;
  187. ERR_CALL_HANDLE(code, fclose(fp));
  188. // писать
  189. code = fwrite(buf, 1, read, fp) == read ? ERR_OK : ERR_FILE_WRITE;
  190. ERR_CALL_HANDLE(code, fclose(fp));
  191. count -= read;
  192. }
  193. // завершение
  194. fclose(fp);
  195. return ERR_OK;
  196. }
  197. /*
  198. *******************************************************************************
  199. Главная функция
  200. *******************************************************************************
  201. */
  202. int esMain(int argc, char* argv[])
  203. {
  204. err_t code;
  205. // справка
  206. if (argc < 2)
  207. return esUsage();
  208. // разбор команды
  209. ++argv, --argc;
  210. if (strEq(argv[0], "print"))
  211. code = esPrint(argc - 1, argv + 1);
  212. else if (strEq(argv[0], "read"))
  213. code = esRead(argc - 1, argv + 1);
  214. else
  215. code = ERR_CMD_NOT_FOUND;
  216. // завершить
  217. if (code != ERR_OK)
  218. printf("bee2cmd/%s: %s\n", _name, errMsg(code));
  219. return (int)code;
  220. }
  221. /*
  222. *******************************************************************************
  223. Инициализация
  224. *******************************************************************************
  225. */
  226. err_t esInit()
  227. {
  228. return cmdReg(_name, _descr, esMain);
  229. }