agievich / bee2
1
/*
2
*******************************************************************************
3
\file botp.с
4
\brief STB 34.101.47/botp: OTP algorithms
5
\project bee2 [cryptographic library]
6
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
7
\created 2015.11.02
8
\version 2020.03.24
9
\license This program is released under the GNU General Public License 
10
version 3. See Copyright Notices in bee2/info.h.
11
*******************************************************************************
12
*/
13

14
#include "bee2/core/blob.h"
15
#include "bee2/core/dec.h"
16
#include "bee2/core/err.h"
17
#include "bee2/core/mem.h"
18
#include "bee2/core/str.h"
19
#include "bee2/core/tm.h"
20
#include "bee2/core/u32.h"
21
#include "bee2/core/util.h"
22
#include "bee2/core/word.h"
23
#include "bee2/math/ww.h"
24
#include "bee2/math/zz.h"
25
#include "bee2/crypto/belt.h"
26
#include "bee2/crypto/botp.h"
27

28
/*
29
*******************************************************************************
30
Вспомогательные функции
31

32
В botpDT() реализован механизм "динамической обрезки" (dynamic truncation),
33
объявленный в RFC 4226 для HMAC(SHA-1), а затем продолженный в RFC 6238, 6287 
34
для HMAC(SHA-256) и HMAC(SHA-512). Пояснений по продолжению нет, но как выяснили
35
экспериментально вот здесь 
36
	http://crypto.stackexchange.com/questions/27474/
37
	[how-does-the-hotp-dynamic-truncation-function-generalize-to-longer-hashes]
38
номер октета, с которого начинается пароль, определяется по последнему октету 
39
mac.
40

41
В RFC 4226/6238 разрешается использовать пароли из 6..8 десятичных символов.
42
В RFC 6287 это требование ослабляется: пароль может дополнительно состоять 
43
из 4, 5, 9, 10 цифр. Ослабление не очень понятно, поскольку имеется только 
44
3 варианта выбора первой (старшей) цифры пароля из 10 цифр: '0', '1' или '2'.
45
В реализации пароли из 10 цифр запрещаются.
46
*******************************************************************************
47
*/
48

49
static const u32 powers_of_10[10] = {
50
	1u,
51
	10u,
52
	100u,
53
	1000u,
54
	10000u,
55
	100000u,
56
	1000000u,
57
	10000000u,
58
	100000000u,
59
	1000000000u,
60
};
61

62 1
void botpDT(char* otp, size_t digit, const octet mac[], size_t mac_len)
63
{
64
	register u32 pwd;
65
	register size_t offset;
66 1
	ASSERT(mac_len >= 20);
67 1
	ASSERT(4 <= digit && digit <= 9);
68 1
	ASSERT(memIsValid(otp, digit + 1));
69 1
	ASSERT(memIsValid(mac, mac_len));
70 1
	offset = mac[mac_len - 1] & 15;
71 1
	pwd = mac[offset], pwd <<= 8;
72 1
	pwd ^= mac[offset + 1], pwd <<= 8;
73 1
	pwd ^= mac[offset + 2], pwd <<= 8;
74 1
	pwd ^= mac[offset + 3];
75 1
	pwd &= 0x7FFFFFFF;
76 1
	pwd %= powers_of_10[digit];
77 1
	decFromU32(otp, digit, pwd);
78 1
	offset = 0;
79 1
	pwd = 0;
80
}
81

82 1
static void botpTimeToCtr(octet ctr[8], tm_time_t t)
83
{
84 1
	ASSERT(sizeof(t) <= 8);
85 1
	memSetZero(ctr, 8 - sizeof(t));
86 1
	memCopy(ctr + 8 - sizeof(t), &t, sizeof(t));
87
#if (OCTET_ORDER == LITTLE_ENDIAN)
88 1
	memRev(ctr + 8 - sizeof(t), sizeof(t));
89
#endif
90
}
91

92 1
void botpCtrNext(octet ctr[8])
93
{
94 1
	register octet carry = 1;
95 1
	ASSERT(memIsValid(ctr, 8));
96 1
	carry = ((ctr[7] += carry) < carry);
97 1
	carry = ((ctr[6] += carry) < carry);
98 1
	carry = ((ctr[5] += carry) < carry);
99 1
	carry = ((ctr[4] += carry) < carry);
100 1
	carry = ((ctr[3] += carry) < carry);
101 1
	carry = ((ctr[2] += carry) < carry);
102 1
	carry = ((ctr[1] += carry) < carry);
103 1
	carry = ((ctr[0] += carry) < carry);
104 1
	carry = 0;
105
}
106

107
/*
108
*******************************************************************************
109
Режим HOTP
110
*******************************************************************************
111
*/
112

113
typedef struct
114
{
115
	size_t digit;		/*< число цифр в пароле */
116
	octet ctr[8];		/*< счетчик */
117
	octet ctr1[8];		/*< копия счетчика */
118
	octet mac[32];		/*< имитовставка */
119
	char otp[10];		/*< текущий пароль */
120
	octet stack[];		/*< [2 * beltHMAC_deep()] */
121
} botp_hotp_st;
122

123 1
size_t botpHOTP_keep()
124
{
125 1
	return sizeof(botp_hotp_st) + 2 * beltHMAC_keep();
126
}
127

128 1
void botpHOTPStart(void* state, size_t digit, const octet key[], 
129
	size_t key_len)
130
{
131 1
	botp_hotp_st* st = (botp_hotp_st*)state;
132 1
	ASSERT(6 <= digit && digit <= 8);
133 1
	ASSERT(memIsDisjoint2(key, key_len, state, botpHOTP_keep()));
134 1
	st->digit = digit;
135 1
	beltHMACStart(st->stack + beltHMAC_keep(), key, key_len);
136
}
137

138 1
void botpHOTPStepS(void* state, const octet ctr[8])
139
{
140 1
	botp_hotp_st* st = (botp_hotp_st*)state;
141 1
	ASSERT(memIsDisjoint2(ctr, 8, state, botpHOTP_keep()) || ctr == st->ctr);
142 1
	memMove(st->ctr, ctr, 8);
143
}
144

145 1
void botpHOTPStepR(char* otp, void* state)
146
{
147 1
	botp_hotp_st* st = (botp_hotp_st*)state;
148
	// pre
149 1
	ASSERT(memIsDisjoint2(otp, st->digit + 1, state, botpHOTP_keep()) || 
150
		otp == st->otp);
151
	// вычислить имитовставку
152 1
	memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep());
153 1
	beltHMACStepA(st->ctr, 8, st->stack);
154 1
	beltHMACStepG(st->mac, st->stack);
155
	// построить пароль
156 1
	botpDT(otp, st->digit, st->mac, 32);
157
	// инкремент счетчика
158 1
	botpCtrNext(st->ctr);
159
}
160

161 1
bool_t botpHOTPStepV(const char* otp, void* state)
162
{
163 1
	botp_hotp_st* st = (botp_hotp_st*)state;
164
	// pre
165 1
	ASSERT(strIsValid(otp));
166 1
	ASSERT(memIsDisjoint2(otp, strLen(otp) + 1, state, botpHOTP_keep()));
167
	// сохранить счетчик
168 1
	memCopy(st->ctr1, st->ctr, 8);
169
	// проверить пароль
170 1
	botpHOTPStepR(st->otp, state);
171 1
	if (strEq(st->otp, otp))
172 1
		return TRUE;
173
	// вернуться к первоначальному счетчику
174 0
	memCopy(st->ctr, st->ctr1, 8);
175 0
	return FALSE;
176
}
177

178 1
void botpHOTPStepG(octet ctr[8], const void* state)
179
{
180 1
	const botp_hotp_st* st = (const botp_hotp_st*)state;
181 1
	ASSERT(memIsDisjoint2(ctr, 8, state, botpHOTP_keep()) || ctr == st->ctr);
182 1
	memMove(ctr, st->ctr, 8);
183
}
184

185 1
err_t botpHOTPRand(char* otp, size_t digit, const octet key[], size_t key_len, 
186
	const octet ctr[8])
187
{
188
	void* state;
189
	// проверить входные данные
190 1
	if (digit < 6 || digit > 8)
191 0
		return ERR_BAD_PARAMS;
192 1
	if (!memIsValid(otp, digit + 1) || 
193 1
		!memIsValid(key, key_len) ||
194 1
		!memIsValid(ctr, 8))
195 0
		return ERR_BAD_INPUT;
196
	// создать состояние
197 1
	state = blobCreate(botpHOTP_keep());
198 1
	if (state == 0)
199 0
		return ERR_OUTOFMEMORY;
200
	// сгенерировать пароль и изменить счетчик
201 1
	botpHOTPStart(state, digit, key, key_len);
202 1
	botpHOTPStepS(state, ctr);
203 1
	botpHOTPStepR(otp, state);
204
	// завершить
205 1
	blobClose(state);
206 1
	return ERR_OK;
207
}
208

209 1
err_t botpHOTPVerify(const char* otp, const octet key[], size_t key_len, 
210
	const octet ctr[8])
211
{
212
	void* state;
213
	bool_t success;
214
	// проверить входные данные
215 1
	if (!strIsValid(otp) || strLen(otp) < 6 || strLen(otp) > 8)
216 0
		return ERR_BAD_PWD;
217 1
	if (!memIsValid(key, key_len) || !memIsValid(ctr, 8))
218 0
		return ERR_BAD_INPUT;
219
	// создать состояние
220 1
	state = blobCreate(botpHOTP_keep());
221 1
	if (state == 0)
222 0
		return ERR_OUTOFMEMORY;
223
	// проверить пароль
224 1
	botpHOTPStart(state, strLen(otp), key, key_len);
225 1
	botpHOTPStepS(state, ctr);
226 1
	success = botpHOTPStepV(otp, state);
227
	// завершить
228 1
	blobClose(state);
229 1
	return success ? ERR_OK : ERR_BAD_PWD;
230
}
231

232
/*
233
*******************************************************************************
234
Режим TOTP
235
*******************************************************************************
236
*/
237

238
typedef struct
239
{
240
	size_t digit;		/*< число цифр в пароле */
241
	octet t[8];			/*< округленная отметка времени */
242
	octet mac[32];		/*< имитовставка */
243
	char otp[10];		/*< текущий пароль */
244
	octet stack[];		/*< [2 * beltHMAC_deep()] */
245
} botp_totp_st;
246

247 1
size_t botpTOTP_keep()
248
{
249 1
	return sizeof(botp_totp_st) + 2 * beltHMAC_keep();
250
}
251

252 1
void botpTOTPStart(void* state, size_t digit, const octet key[], 
253
	size_t key_len)
254
{
255 1
	botp_totp_st* st = (botp_totp_st*)state;
256 1
	ASSERT(6 <= digit && digit <= 8);
257 1
	ASSERT(memIsDisjoint2(key, key_len, state, botpTOTP_keep()));
258 1
	st->digit = digit;
259 1
	beltHMACStart(st->stack + beltHMAC_keep(), key, key_len);
260
}
261

262 1
void botpTOTPStepR(char* otp, tm_time_t t, void* state)
263
{
264 1
	botp_totp_st* st = (botp_totp_st*)state;
265
	// pre
266 1
	ASSERT(t != TIME_ERR);
267 1
	ASSERT(memIsDisjoint2(otp, st->digit + 1, state, botpHOTP_keep()) || 
268
		otp == st->otp);
269
	// вычислить имитовставку
270 1
	memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep());
271 1
	botpTimeToCtr(st->t, t);
272 1
	beltHMACStepA(st->t, 8, st->stack);
273 1
	beltHMACStepG(st->mac, st->stack);
274
	// построить пароль
275 1
	botpDT(otp, st->digit, st->mac, 32);
276
}
277

278 1
bool_t botpTOTPStepV(const char* otp, tm_time_t t, void* state)
279
{
280 1
	botp_totp_st* st = (botp_totp_st*)state;
281
	// pre
282 1
	ASSERT(strIsValid(otp));
283 1
	ASSERT(t != TIME_ERR);
284 1
	ASSERT(memIsDisjoint2(otp, strLen(otp) + 1, state, botpTOTP_keep()));
285
	// вычислить и проверить пароль
286 1
	botpTOTPStepR(st->otp, t, state);
287 1
	return strEq(st->otp, otp);
288
}
289

290 1
err_t botpTOTPRand(char* otp, size_t digit, const octet key[], size_t key_len, 
291
	tm_time_t t)
292
{
293
	void* state;
294
	// проверить входные данные
295 1
	if (digit < 6 || digit > 8)
296 0
		return ERR_BAD_PARAMS;
297 1
	if (t == TIME_ERR)
298 0
		return ERR_BAD_TIME;
299 1
	if (!memIsValid(otp, digit + 1) || 
300 1
		!memIsValid(key, key_len))
301 0
		return ERR_BAD_INPUT;
302
	// создать состояние
303 1
	state = blobCreate(botpTOTP_keep());
304 1
	if (state == 0)
305 0
		return ERR_OUTOFMEMORY;
306
	// сгенерировать пароль
307 1
	botpTOTPStart(state, digit, key, key_len);
308 1
	botpTOTPStepR(otp, t, state);
309
	// завершить
310 1
	blobClose(state);
311 1
	return ERR_OK;
312
}
313

314 1
err_t botpTOTPVerify(const char* otp, const octet key[], size_t key_len, 
315
	tm_time_t t)
316
{
317
	void* state;
318
	bool_t success;
319
	// проверить входные данные
320 1
	if (!strIsValid(otp) || strLen(otp) < 6 || strLen(otp) > 8)
321 0
		return ERR_BAD_PWD;
322 1
	if (t == TIME_ERR)
323 0
		return ERR_BAD_TIME;
324 1
	if (!memIsValid(key, key_len))
325 0
		return ERR_BAD_INPUT;
326
	// создать состояние
327 1
	state = blobCreate(botpTOTP_keep());
328 1
	if (state == 0)
329 0
		return ERR_OUTOFMEMORY;
330
	// проверить пароль
331 1
	botpTOTPStart(state, strLen(otp), key, key_len);
332 1
	success = botpTOTPStepV(otp, t, state);
333
	// завершить
334 1
	blobClose(state);
335 1
	return success ? ERR_OK : ERR_BAD_PWD;
336
}
337

338
/*
339
*******************************************************************************
340
Режим OCRA
341
*******************************************************************************
342
*/
343

344
typedef struct botp_ocra_st
345
{
346
	size_t digit;		/*< число цифр в пароле */
347
	octet ctr[8];		/*< счетчик */
348
	octet ctr1[8];		/*< копия счетчика */
349
	size_t ctr_len;		/*< длина счетчика */
350
	octet q[128];		/*< запрос */
351
	char q_type;		/*< тип запроса (A, N, H) */
352
	size_t q_max;		/*< максимальная длина одиночного запроса */
353
	octet p[64];		/*< хэш-значение статического пароля */
354
	size_t p_len;		/*< длина p */
355
	octet s[512];		/*< идентификатор сеанса */
356
	size_t s_len;		/*< длина идентификатора */
357
	octet t[8];			/*< отметка времени */
358
	tm_time_t ts;		/*< шаг времени */
359
	octet mac[32];		/*< имитовставка */
360
	char otp[10];		/*< текущий пароль */
361
	octet stack[];		/*< [2 * beltHMAC_deep()] */
362
} botp_ocra_st;
363

364 1
size_t botpOCRA_keep()
365
{
366 1
	return sizeof(botp_ocra_st) + 2 * beltHMAC_keep();
367
}
368

369
static const char ocra_prefix[] = "OCRA-1:HOTP-";
370
static const char ocra_hbelt[] = "HBELT";
371
static const char ocra_sha1[] = "SHA1";
372
static const char ocra_sha256[] = "SHA256";
373
static const char ocra_sha512[] = "SHA512";
374

375 1
bool_t botpOCRAStart(void* state, const char* suite, const octet key[], 
376
	size_t key_len)
377
{
378 1
	botp_ocra_st* st = (botp_ocra_st*)state;
379 1
	const char* suite_save = suite;
380
	// pre
381 1
	ASSERT(strIsValid(suite));
382 1
	ASSERT(memIsDisjoint2(suite, strLen(suite) + 1, state, botpOCRA_keep()));
383 1
	ASSERT(memIsDisjoint2(key, key_len, state, botpOCRA_keep()));
384
	// подготовить state
385 1
	memSetZero(st, botpOCRA_keep());
386
	// разбор suite: префикс
387 1
	if (!strStartsWith(suite, ocra_prefix))
388 1
		return FALSE;
389 1
	suite += strLen(ocra_prefix);
390 1
	if (!strStartsWith(suite, ocra_hbelt))
391 0
		return FALSE;
392 1
	suite += strLen(ocra_hbelt);
393 1
	if (*suite++ != '-')
394 0
		return FALSE;
395
	// разбор suite: digit
396 1
	if (*suite < '4' || *suite > '9')
397 1
		return FALSE;
398 1
	st->digit = (size_t)(*suite++ - '0');
399
	// разбор suite: DataInput
400 1
	if (*suite++ != ':')
401 1
		return FALSE;
402
	// разбор suite: ctr
403 1
	if (*suite == 'C')
404
	{
405 1
		if (*++suite != '-')
406 0
			return FALSE;
407 1
		++suite;
408 1
		st->ctr_len = 8;
409
	}
410
	// разбор suite: q
411 1
	if (*suite++ != 'Q')
412 0
		return FALSE;
413 1
	switch (*suite)
414
	{
415
	case 'A':
416
	case 'N':
417
	case 'H':
418 1
		st->q_type = *suite++;
419 1
		break;
420
	default:
421 0
		return FALSE;
422
	}
423 1
	if (suite[0] < '0' || suite[0] > '9' || suite[1] < '0' || suite[1] > '9')
424 0
		return FALSE;
425 1
	st->q_max = (size_t)(suite[0] - '0');
426 1
	st->q_max *= 10, st->q_max += (size_t)(suite[1] - '0');
427 1
	if (st->q_max < 4 || st->q_max > 64)
428 1
		return FALSE;
429 1
	suite += 2;
430
	// разбор suite: p
431 1
	if (strStartsWith(suite, "-P"))
432
	{
433 1
		suite += 2;
434 1
		if (strStartsWith(suite, ocra_hbelt))
435
		{
436 1
			suite += strLen(ocra_hbelt);
437 1
			st->p_len = 32;
438
		}
439 1
		else if (strStartsWith(suite, ocra_sha1))
440
		{
441 0
			suite += strLen(ocra_sha1);
442 0
			st->p_len = 20;
443
		}
444 1
		else if (strStartsWith(suite, ocra_sha256))
445
		{
446 0
			suite += strLen(ocra_sha256);
447 0
			st->p_len = 32;
448
		}
449 1
		else if (strStartsWith(suite, ocra_sha512))
450
		{
451 0
			suite += strLen(ocra_sha512);
452 0
			st->p_len = 64;
453
		}
454
		else
455 1
			return FALSE;
456
	}
457
	// разбор suite: s
458 1
	if (strStartsWith(suite, "-S"))
459
	{
460 1
		suite += 2;
461 1
		if (suite[0] < '0' || suite[0] > '9' || 
462 1
			suite[1] < '0' || suite[1] > '9' ||
463 1
			suite[2] < '0' || suite[2] > '9')
464 1
			return FALSE;
465 1
		st->s_len = (size_t)(suite[0] - '0');
466 1
		st->s_len *= 10, st->s_len += (size_t)(suite[1] - '0');
467 1
		st->s_len *= 10, st->s_len += (size_t)(suite[2] - '0');
468 1
		if (st->s_len > 512)
469 0
			return FALSE;
470 1
		suite += 3;
471
	}
472
	// разбор suite: t
473 1
	if (strStartsWith(suite, "-T"))
474
	{
475 1
		suite += 2;
476 1
		if (*suite < '1' || *suite > '9')
477 0
			return FALSE;
478 1
		st->ts = (size_t)(*suite++ - '0');
479 1
		if (*suite >= '0' && *suite <= '9')
480 1
			st->ts *= 10, st->ts += (size_t)(*suite++ - '0');
481 1
		switch (*suite++)
482
		{
483
		case 'S':
484 1
			if (st->ts > 59)
485 1
				return FALSE;
486 1
			break;
487
		case 'M':
488 1
			if (st->ts > 59)
489 0
				return FALSE;
490 1
			st->ts *= 60;
491 1
			break;
492
		case 'H':
493 1
			if (st->ts > 48)
494 1
				return FALSE;
495 0
			st->ts *= 3600;
496 0
			break;
497
		default:
498 1
			return FALSE;
499
		}
500
	}
501
	// разбор suite: окончание
502 1
	if (*suite)
503 1
		return FALSE;
504
	// запуск HMAC 
505 1
	beltHMACStart(st->stack + beltHMAC_keep(), key, key_len);
506 1
	beltHMACStepA(suite_save, strLen(suite_save) + 1,
507 1
		st->stack + beltHMAC_keep());
508 1
	return TRUE;
509
}
510

511 1
void botpOCRAStepS(void* state, const octet ctr[8], const octet p[], 
512
	const octet s[])
513
{
514 1
	botp_ocra_st* st = (botp_ocra_st*)state;
515
	// pre
516 1
	ASSERT(memIsValid(state, botpOCRA_keep()));
517
	// загрузить сtr
518 1
	if (st->ctr_len)
519
	{
520 1
		ASSERT(memIsDisjoint2(ctr, 8, st, botpOCRA_keep()) || ctr == st->ctr);
521 1
		memMove(st->ctr, ctr, 8);
522
	}
523
	// загрузить p
524 1
	if (st->p_len)
525
	{
526 1
		ASSERT(memIsDisjoint2(p, st->p_len, st, botpOCRA_keep()) || p == st->p);
527 1
		memMove(st->p, p, st->p_len);
528
	}
529
	// загрузить s
530 1
	if (st->s_len)
531
	{
532 1
		ASSERT(memIsDisjoint2(p, st->s_len, s, botpOCRA_keep()) || s == st->s);
533 1
		memMove(st->s, s, st->s_len);
534
	}
535
}
536

537 1
void botpOCRAStepR(char* otp, const octet q[], size_t q_len, tm_time_t t, 
538
	void* state)
539
{
540 1
	botp_ocra_st* st = (botp_ocra_st*)state;
541
	// pre
542 1
	ASSERT(memIsDisjoint2(otp, st->digit + 1, state, botpOCRA_keep()) || 
543
		otp == st->otp);
544 1
	ASSERT(4 <= q_len && q_len <= 2 * st->q_max);
545 1
	ASSERT(memIsDisjoint2(q, q_len, state, botpOCRA_keep() || q == st->q));
546 1
	ASSERT(t != TIME_ERR);
547
	// вычислить имитовставку
548 1
	memCopy(st->stack, st->stack + beltHMAC_keep(), beltHMAC_keep());
549 1
	if (st->ctr_len)
550 1
		beltHMACStepA(st->ctr, 8, st->stack), botpCtrNext(st->ctr);
551 1
	memMove(st->q, q, q_len);
552 1
	memSetZero(st->q + q_len, 128 - q_len);
553 1
	beltHMACStepA(st->q, 128, st->stack);
554 1
	if (st->p_len)
555 1
		beltHMACStepA(st->p, st->p_len, st->stack);
556 1
	if (st->s_len)
557 1
		beltHMACStepA(st->s, st->s_len, st->stack);
558 1
	if (st->ts)
559 1
		botpTimeToCtr(st->t, t), beltHMACStepA(st->t, 8, st->stack);
560 1
	beltHMACStepG(st->mac, st->stack);
561
	// построить пароль
562 1
	botpDT(otp, st->digit, st->mac, 32);
563
}
564

565 1
bool_t botpOCRAStepV(const char* otp, const octet q[], size_t q_len, 
566
	tm_time_t t, void* state)
567
{
568 1
	botp_ocra_st* st = (botp_ocra_st*)state;
569
	// pre
570 1
	ASSERT(strIsValid(otp));
571 1
	ASSERT(memIsDisjoint2(otp, strLen(otp) + 1, state, botpOCRA_keep()));
572
	// сохранить счетчик
573 1
	memCopy(st->ctr1, st->ctr, 8);
574
	// проверить пароль
575 1
	botpOCRAStepR(st->otp, q, q_len, t, state);
576 1
	if (strEq(st->otp, otp))
577 1
		return TRUE;
578
	// вернуться к первоначальному счетчику
579 0
	memCopy(st->ctr, st->ctr1, 8);
580 0
	return FALSE;
581
}
582

583 1
void botpOCRAStepG(octet ctr[8], const void* state)
584
{
585 1
	const botp_ocra_st* st = (const botp_ocra_st*)state;
586 1
	ASSERT(memIsDisjoint2(ctr, 8, state, botpOCRA_keep()) || ctr == st->ctr);
587 1
	memMove(ctr, st->ctr, 8);
588
}
589

590 1
err_t botpOCRARand(char* otp, const char* suite, const octet key[],	
591
	size_t key_len, const octet q[], size_t q_len, const octet ctr[8], 
592
	const octet p[], const octet s[], tm_time_t t)
593
{
594
	botp_ocra_st* state;
595
	// предварительно проверить входные данные
596 1
	if (!strIsValid(suite) || !memIsValid(key, key_len))
597 0
		return ERR_BAD_INPUT;
598
	// создать состояние
599 1
	state = (botp_ocra_st*)blobCreate(botpOCRA_keep());
600 1
	if (state == 0)
601 0
		return ERR_OUTOFMEMORY;
602
	// разобрать suite
603 1
	if (!botpOCRAStart(state, suite, key, key_len))
604
	{
605 0
		blobClose(state);
606 0
		return ERR_BAD_FORMAT;
607
	}
608
	// проверить q_len
609 1
	if (q_len < 4 || q_len > 2 * state->q_max)
610
	{
611 0
		blobClose(state);
612 0
		return ERR_BAD_PARAMS;
613
	}
614
	// полностью проверить входные данные
615 1
	if (!memIsValid(otp, state->digit + 1) ||
616 1
		state->ctr_len && !memIsValid(ctr, state->ctr_len) ||
617 1
		!memIsValid(q, q_len) ||
618 1
		state->p_len && !memIsValid(p, state->p_len) ||
619 1
		state->s_len && !memIsValid(s, state->s_len))
620
	{
621 0
		blobClose(state);
622 0
		return ERR_BAD_INPUT;
623
	}
624 1
	if (state->ts && t == TIME_ERR)
625
	{
626 0
		blobClose(state);
627 0
		return ERR_BAD_TIME;
628
	}
629
	// сгенерировать пароль
630 1
	botpOCRAStepS(state, ctr, p, s);
631 1
	botpOCRAStepR(otp, q, q_len, t, state);
632
	// завершить
633 1
	blobClose(state);
634 1
	return ERR_OK;
635
}
636

637 1
err_t botpOCRAVerify(const char* otp, const char* suite, const octet key[], 
638
	size_t key_len, const octet q[], size_t q_len, const octet ctr[8], 
639
	const octet p[], const octet s[], tm_time_t t)
640
{
641
	botp_ocra_st* state;
642
	bool_t success;
643
	// предварительно проверить входные данные
644 1
	if (!strIsValid(suite) || !memIsValid(key, key_len))
645 0
		return ERR_BAD_INPUT;
646
	// создать состояние
647 1
	state = (botp_ocra_st*)blobCreate(botpOCRA_keep());
648 1
	if (state == 0)
649 0
		return ERR_OUTOFMEMORY;
650
	// разобрать suite
651 1
	if (!botpOCRAStart(state, suite, key, key_len))
652
	{
653 0
		blobClose(state);
654 0
		return ERR_BAD_FORMAT;
655
	}
656
	// проверить q_len
657 1
	if (q_len < 4 || q_len > 2 * state->q_max)
658
	{
659 0
		blobClose(state);
660 0
		return ERR_BAD_PARAMS;
661
	}
662
	// полностью проверить входные данные
663 1
	if (state->digit != strLen(otp))
664
	{
665 0
		blobClose(state);
666 0
		return ERR_BAD_PWD;
667
	}
668 1
	if (!memIsValid(otp, state->digit + 1) ||
669 1
		state->ctr_len && !memIsValid(ctr, state->ctr_len) ||
670 1
		!memIsValid(q, q_len) ||
671 1
		state->p_len && !memIsValid(p, state->p_len) ||
672 1
		state->s_len && !memIsValid(s, state->s_len))
673
	{
674 0
		blobClose(state);
675 0
		return ERR_BAD_INPUT;
676
	}
677 1
	if (state->ts && t == TIME_ERR)
678
	{
679 0
		blobClose(state);
680 0
		return ERR_BAD_TIME;
681
	}
682
	// проверить пароль
683 1
	botpOCRAStepS(state, ctr, p, s);
684 1
	success = botpOCRAStepV(otp, q, q_len, t, state);
685
	// завершить
686 1
	blobClose(state);
687 1
	return success ? ERR_OK : ERR_BAD_PWD;
688
}

Read our documentation on viewing source code .

Loading