OTPChecker.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /**
  2. * @file OTPChecker.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <string.h>
  23. #include <misc/balloc.h>
  24. #include <security/OTPChecker.h>
  25. static void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t);
  26. static void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp);
  27. static void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv);
  28. static int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp);
  29. void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t)
  30. {
  31. for (int i = 0; i < mc->num_entries; i++) {
  32. t->entries[i].avail = -1;
  33. }
  34. }
  35. void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp)
  36. {
  37. // calculate starting index
  38. int start_index = otp % mc->num_entries;
  39. // try indexes starting with the base position
  40. for (int i = 0; i < mc->num_entries; i++) {
  41. int index = bmodadd_int(start_index, i, mc->num_entries);
  42. struct OTPChecker_entry *entry = &t->entries[index];
  43. // if we find a free index, use it
  44. if (entry->avail < 0) {
  45. entry->otp = otp;
  46. entry->avail = 1;
  47. return;
  48. }
  49. // if we find a used index with the same mac,
  50. // use it by incrementing its count
  51. if (entry->otp == otp) {
  52. entry->avail++;
  53. return;
  54. }
  55. }
  56. // will never add more macs than we can hold
  57. ASSERT(0)
  58. }
  59. void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv)
  60. {
  61. // calculate values
  62. otp_t *otps = OTPCalculator_Generate(calc, key, iv, 0);
  63. // empty table
  64. OTPChecker_Table_Empty(mc ,t);
  65. // add calculated values to table
  66. for (int i = 0; i < mc->num_otps; i++) {
  67. OTPChecker_Table_AddOTP(mc, t, otps[i]);
  68. }
  69. }
  70. int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp)
  71. {
  72. // calculate starting index
  73. int start_index = otp % mc->num_entries;
  74. // try indexes starting with the base position
  75. for (int i = 0; i < mc->num_entries; i++) {
  76. int index = bmodadd_int(start_index, i, mc->num_entries);
  77. struct OTPChecker_entry *entry = &t->entries[index];
  78. // if we find an empty entry, there is no such mac
  79. if (entry->avail < 0) {
  80. return 0;
  81. }
  82. // if we find a matching entry, check its count
  83. if (entry->otp == otp) {
  84. if (entry->avail > 0) {
  85. entry->avail--;
  86. return 1;
  87. }
  88. return 0;
  89. }
  90. }
  91. // there are always empty slots
  92. ASSERT(0)
  93. return 0;
  94. }
  95. static void work_func (OTPChecker *mc)
  96. {
  97. struct OTPChecker_table *table = &mc->tables[mc->next_table];
  98. OTPChecker_Table_Generate(mc, table, &mc->calc, mc->tw_key, mc->tw_iv);
  99. }
  100. static void work_done_handler (OTPChecker *mc)
  101. {
  102. ASSERT(mc->tw_have)
  103. DebugObject_Access(&mc->d_obj);
  104. // free work
  105. BThreadWork_Free(&mc->tw);
  106. mc->tw_have = 0;
  107. // update next table number
  108. mc->next_table = bmodadd_int(mc->next_table, 1, mc->num_tables);
  109. // update number of used tables if not all are used yet
  110. if (mc->tables_used < mc->num_tables) {
  111. mc->tables_used++;
  112. }
  113. // call handler
  114. if (mc->handler) {
  115. mc->handler(mc->user);
  116. return;
  117. }
  118. }
  119. int OTPChecker_Init (OTPChecker *mc, int num_otps, int cipher, int num_tables, BThreadWorkDispatcher *twd)
  120. {
  121. ASSERT(num_otps > 0)
  122. ASSERT(BEncryption_cipher_valid(cipher))
  123. ASSERT(num_tables > 0)
  124. // init arguments
  125. mc->num_otps = num_otps;
  126. mc->cipher = cipher;
  127. mc->num_tables = num_tables;
  128. mc->twd = twd;
  129. // set no handlers
  130. mc->handler = NULL;
  131. // set number of entries
  132. if (mc->num_otps > INT_MAX / 2) {
  133. goto fail0;
  134. }
  135. mc->num_entries = 2 * mc->num_otps;
  136. // set no tables used
  137. mc->tables_used = 0;
  138. mc->next_table = 0;
  139. // initialize calculator
  140. if (!OTPCalculator_Init(&mc->calc, mc->num_otps, cipher)) {
  141. goto fail0;
  142. }
  143. // allocate tables
  144. if (!(mc->tables = BAllocArray(mc->num_tables, sizeof(mc->tables[0])))) {
  145. goto fail1;
  146. }
  147. // allocate entries
  148. if (!(mc->entries = BAllocArray2(mc->num_tables, mc->num_entries, sizeof(mc->entries[0])))) {
  149. goto fail2;
  150. }
  151. // initialize tables
  152. for (int i = 0; i < mc->num_tables; i++) {
  153. struct OTPChecker_table *table = &mc->tables[i];
  154. table->entries = mc->entries + (size_t)i * mc->num_entries;
  155. OTPChecker_Table_Empty(mc, table);
  156. }
  157. // have no work
  158. mc->tw_have = 0;
  159. DebugObject_Init(&mc->d_obj);
  160. return 1;
  161. fail2:
  162. BFree(mc->tables);
  163. fail1:
  164. OTPCalculator_Free(&mc->calc);
  165. fail0:
  166. return 0;
  167. }
  168. void OTPChecker_Free (OTPChecker *mc)
  169. {
  170. DebugObject_Free(&mc->d_obj);
  171. // free work
  172. if (mc->tw_have) {
  173. BThreadWork_Free(&mc->tw);
  174. }
  175. // free entries
  176. BFree(mc->entries);
  177. // free tables
  178. BFree(mc->tables);
  179. // free calculator
  180. OTPCalculator_Free(&mc->calc);
  181. }
  182. void OTPChecker_AddSeed (OTPChecker *mc, uint16_t seed_id, uint8_t *key, uint8_t *iv)
  183. {
  184. ASSERT(mc->next_table >= 0)
  185. ASSERT(mc->next_table < mc->num_tables)
  186. DebugObject_Access(&mc->d_obj);
  187. // free existing work
  188. if (mc->tw_have) {
  189. BThreadWork_Free(&mc->tw);
  190. }
  191. // set table's seed ID
  192. mc->tables[mc->next_table].id = seed_id;
  193. // copy key and IV
  194. memcpy(mc->tw_key, key, BEncryption_cipher_key_size(mc->cipher));
  195. memcpy(mc->tw_iv, iv, BEncryption_cipher_block_size(mc->cipher));
  196. // start work
  197. BThreadWork_Init(&mc->tw, mc->twd, (BThreadWork_handler_done)work_done_handler, mc, (BThreadWork_work_func)work_func, mc);
  198. // set have work
  199. mc->tw_have = 1;
  200. }
  201. void OTPChecker_RemoveSeeds (OTPChecker *mc)
  202. {
  203. DebugObject_Access(&mc->d_obj);
  204. // free existing work
  205. if (mc->tw_have) {
  206. BThreadWork_Free(&mc->tw);
  207. mc->tw_have = 0;
  208. }
  209. mc->tables_used = 0;
  210. mc->next_table = 0;
  211. }
  212. int OTPChecker_CheckOTP (OTPChecker *mc, uint16_t seed_id, otp_t otp)
  213. {
  214. DebugObject_Access(&mc->d_obj);
  215. // try tables in reverse order
  216. for (int i = 1; i <= mc->tables_used; i++) {
  217. int table_index = bmodadd_int(mc->next_table, mc->num_tables - i, mc->num_tables);
  218. if (table_index == mc->next_table && mc->tw_have) {
  219. // ignore table that is being generated
  220. continue;
  221. }
  222. struct OTPChecker_table *table = &mc->tables[table_index];
  223. if (table->id == seed_id) {
  224. return OTPChecker_Table_CheckOTP(mc, table, otp);
  225. }
  226. }
  227. return 0;
  228. }
  229. void OTPChecker_SetHandlers (OTPChecker *mc, OTPChecker_handler handler, void *user)
  230. {
  231. DebugObject_Access(&mc->d_obj);
  232. mc->handler = handler;
  233. mc->user = user;
  234. }