OTPChecker.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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 <security/OTPChecker.h>
  24. static void OTPChecker_Table_Empty (OTPChecker *mc, oc_table *t);
  25. static void OTPChecker_Table_AddOTP (OTPChecker *mc, oc_table *t, otp_t otp);
  26. static void OTPChecker_Table_Generate (OTPChecker *mc, oc_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv);
  27. static int OTPChecker_Table_CheckOTP (OTPChecker *mc, oc_table *t, otp_t otp);
  28. void OTPChecker_Table_Empty (OTPChecker *mc, oc_table *t)
  29. {
  30. for (int i = 0; i < mc->num_entries; i++) {
  31. oc_table_entries_at(&mc->tables_params.tables_params, t, i)->avail = -1;
  32. }
  33. }
  34. void OTPChecker_Table_AddOTP (OTPChecker *mc, oc_table *t, otp_t otp)
  35. {
  36. // calculate starting index
  37. int start_index = otp % mc->num_entries;
  38. // try indexes starting with the base position
  39. for (int i = 0; i < mc->num_entries; i++) {
  40. int index = BMODADD(start_index, i, mc->num_entries);
  41. struct OTPChecker_entry *entry = oc_table_entries_at(&mc->tables_params.tables_params, t, index);
  42. // if we find a free index, use it
  43. if (entry->avail < 0) {
  44. entry->otp = otp;
  45. entry->avail = 1;
  46. return;
  47. }
  48. // if we find a used index with the same mac,
  49. // use it by incrementing its count
  50. if (entry->otp == otp) {
  51. entry->avail++;
  52. return;
  53. }
  54. }
  55. // will never add more macs than we can hold
  56. ASSERT(0)
  57. }
  58. void OTPChecker_Table_Generate (OTPChecker *mc, oc_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv)
  59. {
  60. // calculate values
  61. otp_t *otps = OTPCalculator_Generate(calc, key, iv, 0);
  62. // empty table
  63. OTPChecker_Table_Empty(mc ,t);
  64. // add calculated values to table
  65. for (int i = 0; i < mc->num_otps; i++) {
  66. OTPChecker_Table_AddOTP(mc, t, otps[i]);
  67. }
  68. }
  69. int OTPChecker_Table_CheckOTP (OTPChecker *mc, oc_table *t, otp_t otp)
  70. {
  71. // calculate starting index
  72. int start_index = otp % mc->num_entries;
  73. // try indexes starting with the base position
  74. for (int i = 0; i < mc->num_entries; i++) {
  75. int index = BMODADD(start_index, i, mc->num_entries);
  76. struct OTPChecker_entry *entry = oc_table_entries_at(&mc->tables_params.tables_params, t, index);
  77. // if we find an empty entry, there is no such mac
  78. if (entry->avail < 0) {
  79. return 0;
  80. }
  81. // if we find a matching entry, check its count
  82. if (entry->otp == otp) {
  83. if (entry->avail > 0) {
  84. entry->avail--;
  85. return 1;
  86. }
  87. return 0;
  88. }
  89. }
  90. // there are always empty slots
  91. ASSERT(0)
  92. return 0;
  93. }
  94. static void work_func (OTPChecker *mc)
  95. {
  96. oc_table *table = oc_tables_tables_at(&mc->tables_params, mc->tables, mc->next_table);
  97. OTPChecker_Table_Generate(mc, table, &mc->calc, mc->tw_key, mc->tw_iv);
  98. }
  99. static void work_done_handler (OTPChecker *mc)
  100. {
  101. ASSERT(mc->tw_have)
  102. DebugObject_Access(&mc->d_obj);
  103. // free work
  104. BThreadWork_Free(&mc->tw);
  105. mc->tw_have = 0;
  106. // update next table number
  107. mc->next_table = BMODADD(mc->next_table, 1, mc->num_tables);
  108. // update number of used tables if not all are used yet
  109. if (mc->tables_used < mc->num_tables) {
  110. mc->tables_used++;
  111. }
  112. // call handler
  113. if (mc->handler) {
  114. mc->handler(mc->user);
  115. return;
  116. }
  117. }
  118. int OTPChecker_Init (OTPChecker *mc, int num_otps, int cipher, int num_tables, BThreadWorkDispatcher *twd)
  119. {
  120. ASSERT(num_otps > 0)
  121. ASSERT(BEncryption_cipher_valid(cipher))
  122. ASSERT(num_tables > 0)
  123. // init arguments
  124. mc->num_otps = num_otps;
  125. mc->cipher = cipher;
  126. mc->num_tables = num_tables;
  127. mc->twd = twd;
  128. // set no handlers
  129. mc->handler = NULL;
  130. // set number of entries
  131. mc->num_entries = 2 * mc->num_otps;
  132. // set no tables used
  133. mc->tables_used = 0;
  134. mc->next_table = 0;
  135. // initialize calculator
  136. if (!OTPCalculator_Init(&mc->calc, mc->num_otps, cipher)) {
  137. goto fail0;
  138. }
  139. // allocate tables
  140. oc_tablesParams_Init(&mc->tables_params, mc->num_tables, mc->num_entries);
  141. if (!(mc->tables = malloc(mc->tables_params.len))) {
  142. goto fail1;
  143. }
  144. // initialize tables
  145. for (int i = 0; i < mc->num_tables; i++) {
  146. OTPChecker_Table_Empty(mc, oc_tables_tables_at(&mc->tables_params, mc->tables, i));
  147. }
  148. // have no work
  149. mc->tw_have = 0;
  150. DebugObject_Init(&mc->d_obj);
  151. return 1;
  152. fail1:
  153. OTPCalculator_Free(&mc->calc);
  154. fail0:
  155. return 0;
  156. }
  157. void OTPChecker_Free (OTPChecker *mc)
  158. {
  159. DebugObject_Free(&mc->d_obj);
  160. // free work
  161. if (mc->tw_have) {
  162. BThreadWork_Free(&mc->tw);
  163. }
  164. // free tables
  165. free(mc->tables);
  166. // free calculator
  167. OTPCalculator_Free(&mc->calc);
  168. }
  169. void OTPChecker_AddSeed (OTPChecker *mc, uint16_t seed_id, uint8_t *key, uint8_t *iv)
  170. {
  171. ASSERT(mc->next_table >= 0)
  172. ASSERT(mc->next_table < mc->num_tables)
  173. DebugObject_Access(&mc->d_obj);
  174. // free existing work
  175. if (mc->tw_have) {
  176. BThreadWork_Free(&mc->tw);
  177. }
  178. // set table's seed ID
  179. oc_table *table = oc_tables_tables_at(&mc->tables_params, mc->tables, mc->next_table);
  180. *oc_table_id(&mc->tables_params.tables_params, table) = seed_id;
  181. // copy key and IV
  182. memcpy(mc->tw_key, key, BEncryption_cipher_key_size(mc->cipher));
  183. memcpy(mc->tw_iv, iv, BEncryption_cipher_block_size(mc->cipher));
  184. // start work
  185. BThreadWork_Init(&mc->tw, mc->twd, (BThreadWork_handler_done)work_done_handler, mc, (BThreadWork_work_func)work_func, mc);
  186. // set have work
  187. mc->tw_have = 1;
  188. }
  189. void OTPChecker_RemoveSeeds (OTPChecker *mc)
  190. {
  191. DebugObject_Access(&mc->d_obj);
  192. // free existing work
  193. if (mc->tw_have) {
  194. BThreadWork_Free(&mc->tw);
  195. mc->tw_have = 0;
  196. }
  197. mc->tables_used = 0;
  198. mc->next_table = 0;
  199. }
  200. int OTPChecker_CheckOTP (OTPChecker *mc, uint16_t seed_id, otp_t otp)
  201. {
  202. DebugObject_Access(&mc->d_obj);
  203. // try tables in reverse order
  204. for (int i = 1; i <= mc->tables_used; i++) {
  205. int table_index = BMODADD(mc->next_table, mc->num_tables - i, mc->num_tables);
  206. if (table_index == mc->next_table && mc->tw_have) {
  207. // ignore table that is being generated
  208. continue;
  209. }
  210. oc_table *table = oc_tables_tables_at(&mc->tables_params, mc->tables, table_index);
  211. if (*oc_table_id(&mc->tables_params.tables_params, table) == seed_id) {
  212. return OTPChecker_Table_CheckOTP(mc, table, otp);
  213. }
  214. }
  215. return 0;
  216. }
  217. void OTPChecker_SetHandlers (OTPChecker *mc, OTPChecker_handler handler, void *user)
  218. {
  219. DebugObject_Access(&mc->d_obj);
  220. mc->handler = handler;
  221. mc->user = user;
  222. }