BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file OTPChecker.c |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | */ |
||
29 | |||
30 | #include <string.h> |
||
31 | |||
32 | #include <misc/balloc.h> |
||
33 | |||
34 | #include <security/OTPChecker.h> |
||
35 | |||
36 | static void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t); |
||
37 | static void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp); |
||
38 | static void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv); |
||
39 | static int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp); |
||
40 | |||
41 | void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t) |
||
42 | { |
||
43 | for (int i = 0; i < mc->num_entries; i++) { |
||
44 | t->entries[i].avail = -1; |
||
45 | } |
||
46 | } |
||
47 | |||
48 | void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp) |
||
49 | { |
||
50 | // calculate starting index |
||
51 | int start_index = otp % mc->num_entries; |
||
52 | |||
53 | // try indexes starting with the base position |
||
54 | for (int i = 0; i < mc->num_entries; i++) { |
||
55 | int index = bmodadd_int(start_index, i, mc->num_entries); |
||
56 | struct OTPChecker_entry *entry = &t->entries[index]; |
||
57 | |||
58 | // if we find a free index, use it |
||
59 | if (entry->avail < 0) { |
||
60 | entry->otp = otp; |
||
61 | entry->avail = 1; |
||
62 | return; |
||
63 | } |
||
64 | |||
65 | // if we find a used index with the same mac, |
||
66 | // use it by incrementing its count |
||
67 | if (entry->otp == otp) { |
||
68 | entry->avail++; |
||
69 | return; |
||
70 | } |
||
71 | } |
||
72 | |||
73 | // will never add more macs than we can hold |
||
74 | ASSERT(0) |
||
75 | } |
||
76 | |||
77 | void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv) |
||
78 | { |
||
79 | // calculate values |
||
80 | otp_t *otps = OTPCalculator_Generate(calc, key, iv, 0); |
||
81 | |||
82 | // empty table |
||
83 | OTPChecker_Table_Empty(mc ,t); |
||
84 | |||
85 | // add calculated values to table |
||
86 | for (int i = 0; i < mc->num_otps; i++) { |
||
87 | OTPChecker_Table_AddOTP(mc, t, otps[i]); |
||
88 | } |
||
89 | } |
||
90 | |||
91 | int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp) |
||
92 | { |
||
93 | // calculate starting index |
||
94 | int start_index = otp % mc->num_entries; |
||
95 | |||
96 | // try indexes starting with the base position |
||
97 | for (int i = 0; i < mc->num_entries; i++) { |
||
98 | int index = bmodadd_int(start_index, i, mc->num_entries); |
||
99 | struct OTPChecker_entry *entry = &t->entries[index]; |
||
100 | |||
101 | // if we find an empty entry, there is no such mac |
||
102 | if (entry->avail < 0) { |
||
103 | return 0; |
||
104 | } |
||
105 | |||
106 | // if we find a matching entry, check its count |
||
107 | if (entry->otp == otp) { |
||
108 | if (entry->avail > 0) { |
||
109 | entry->avail--; |
||
110 | return 1; |
||
111 | } |
||
112 | return 0; |
||
113 | } |
||
114 | } |
||
115 | |||
116 | // there are always empty slots |
||
117 | ASSERT(0) |
||
118 | return 0; |
||
119 | } |
||
120 | |||
121 | static void work_func (OTPChecker *mc) |
||
122 | { |
||
123 | struct OTPChecker_table *table = &mc->tables[mc->next_table]; |
||
124 | OTPChecker_Table_Generate(mc, table, &mc->calc, mc->tw_key, mc->tw_iv); |
||
125 | } |
||
126 | |||
127 | static void work_done_handler (OTPChecker *mc) |
||
128 | { |
||
129 | ASSERT(mc->tw_have) |
||
130 | DebugObject_Access(&mc->d_obj); |
||
131 | |||
132 | // free work |
||
133 | BThreadWork_Free(&mc->tw); |
||
134 | mc->tw_have = 0; |
||
135 | |||
136 | // update next table number |
||
137 | mc->next_table = bmodadd_int(mc->next_table, 1, mc->num_tables); |
||
138 | |||
139 | // update number of used tables if not all are used yet |
||
140 | if (mc->tables_used < mc->num_tables) { |
||
141 | mc->tables_used++; |
||
142 | } |
||
143 | |||
144 | // call handler |
||
145 | if (mc->handler) { |
||
146 | mc->handler(mc->user); |
||
147 | return; |
||
148 | } |
||
149 | } |
||
150 | |||
151 | int OTPChecker_Init (OTPChecker *mc, int num_otps, int cipher, int num_tables, BThreadWorkDispatcher *twd) |
||
152 | { |
||
153 | ASSERT(num_otps > 0) |
||
154 | ASSERT(BEncryption_cipher_valid(cipher)) |
||
155 | ASSERT(num_tables > 0) |
||
156 | |||
157 | // init arguments |
||
158 | mc->num_otps = num_otps; |
||
159 | mc->cipher = cipher; |
||
160 | mc->num_tables = num_tables; |
||
161 | mc->twd = twd; |
||
162 | |||
163 | // set no handlers |
||
164 | mc->handler = NULL; |
||
165 | |||
166 | // set number of entries |
||
167 | if (mc->num_otps > INT_MAX / 2) { |
||
168 | goto fail0; |
||
169 | } |
||
170 | mc->num_entries = 2 * mc->num_otps; |
||
171 | |||
172 | // set no tables used |
||
173 | mc->tables_used = 0; |
||
174 | mc->next_table = 0; |
||
175 | |||
176 | // initialize calculator |
||
177 | if (!OTPCalculator_Init(&mc->calc, mc->num_otps, cipher)) { |
||
178 | goto fail0; |
||
179 | } |
||
180 | |||
181 | // allocate tables |
||
182 | if (!(mc->tables = (struct OTPChecker_table *)BAllocArray(mc->num_tables, sizeof(mc->tables[0])))) { |
||
183 | goto fail1; |
||
184 | } |
||
185 | |||
186 | // allocate entries |
||
187 | if (!(mc->entries = (struct OTPChecker_entry *)BAllocArray2(mc->num_tables, mc->num_entries, sizeof(mc->entries[0])))) { |
||
188 | goto fail2; |
||
189 | } |
||
190 | |||
191 | // initialize tables |
||
192 | for (int i = 0; i < mc->num_tables; i++) { |
||
193 | struct OTPChecker_table *table = &mc->tables[i]; |
||
194 | table->entries = mc->entries + (size_t)i * mc->num_entries; |
||
195 | OTPChecker_Table_Empty(mc, table); |
||
196 | } |
||
197 | |||
198 | // have no work |
||
199 | mc->tw_have = 0; |
||
200 | |||
201 | DebugObject_Init(&mc->d_obj); |
||
202 | return 1; |
||
203 | |||
204 | fail2: |
||
205 | BFree(mc->tables); |
||
206 | fail1: |
||
207 | OTPCalculator_Free(&mc->calc); |
||
208 | fail0: |
||
209 | return 0; |
||
210 | } |
||
211 | |||
212 | void OTPChecker_Free (OTPChecker *mc) |
||
213 | { |
||
214 | DebugObject_Free(&mc->d_obj); |
||
215 | |||
216 | // free work |
||
217 | if (mc->tw_have) { |
||
218 | BThreadWork_Free(&mc->tw); |
||
219 | } |
||
220 | |||
221 | // free entries |
||
222 | BFree(mc->entries); |
||
223 | |||
224 | // free tables |
||
225 | BFree(mc->tables); |
||
226 | |||
227 | // free calculator |
||
228 | OTPCalculator_Free(&mc->calc); |
||
229 | } |
||
230 | |||
231 | void OTPChecker_AddSeed (OTPChecker *mc, uint16_t seed_id, uint8_t *key, uint8_t *iv) |
||
232 | { |
||
233 | ASSERT(mc->next_table >= 0) |
||
234 | ASSERT(mc->next_table < mc->num_tables) |
||
235 | DebugObject_Access(&mc->d_obj); |
||
236 | |||
237 | // free existing work |
||
238 | if (mc->tw_have) { |
||
239 | BThreadWork_Free(&mc->tw); |
||
240 | } |
||
241 | |||
242 | // set table's seed ID |
||
243 | mc->tables[mc->next_table].id = seed_id; |
||
244 | |||
245 | // copy key and IV |
||
246 | memcpy(mc->tw_key, key, BEncryption_cipher_key_size(mc->cipher)); |
||
247 | memcpy(mc->tw_iv, iv, BEncryption_cipher_block_size(mc->cipher)); |
||
248 | |||
249 | // start work |
||
250 | BThreadWork_Init(&mc->tw, mc->twd, (BThreadWork_handler_done)work_done_handler, mc, (BThreadWork_work_func)work_func, mc); |
||
251 | |||
252 | // set have work |
||
253 | mc->tw_have = 1; |
||
254 | } |
||
255 | |||
256 | void OTPChecker_RemoveSeeds (OTPChecker *mc) |
||
257 | { |
||
258 | DebugObject_Access(&mc->d_obj); |
||
259 | |||
260 | // free existing work |
||
261 | if (mc->tw_have) { |
||
262 | BThreadWork_Free(&mc->tw); |
||
263 | mc->tw_have = 0; |
||
264 | } |
||
265 | |||
266 | mc->tables_used = 0; |
||
267 | mc->next_table = 0; |
||
268 | } |
||
269 | |||
270 | int OTPChecker_CheckOTP (OTPChecker *mc, uint16_t seed_id, otp_t otp) |
||
271 | { |
||
272 | DebugObject_Access(&mc->d_obj); |
||
273 | |||
274 | // try tables in reverse order |
||
275 | for (int i = 1; i <= mc->tables_used; i++) { |
||
276 | int table_index = bmodadd_int(mc->next_table, mc->num_tables - i, mc->num_tables); |
||
277 | if (table_index == mc->next_table && mc->tw_have) { |
||
278 | // ignore table that is being generated |
||
279 | continue; |
||
280 | } |
||
281 | |||
282 | struct OTPChecker_table *table = &mc->tables[table_index]; |
||
283 | if (table->id == seed_id) { |
||
284 | return OTPChecker_Table_CheckOTP(mc, table, otp); |
||
285 | } |
||
286 | } |
||
287 | |||
288 | return 0; |
||
289 | } |
||
290 | |||
291 | void OTPChecker_SetHandlers (OTPChecker *mc, OTPChecker_handler handler, void *user) |
||
292 | { |
||
293 | DebugObject_Access(&mc->d_obj); |
||
294 | |||
295 | mc->handler = handler; |
||
296 | mc->user = user; |
||
297 | } |