1
|
|
/*
|
2
|
|
*******************************************************************************
|
3
|
|
\file brng.c
|
4
|
|
\brief STB 34.101.47 (brng): algorithms of pseudorandom number generation
|
5
|
|
\project bee2 [cryptographic library]
|
6
|
|
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
|
7
|
|
\created 2013.01.31
|
8
|
|
\version 2018.07.09
|
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/err.h"
|
16
|
|
#include "bee2/core/mem.h"
|
17
|
|
#include "bee2/core/util.h"
|
18
|
|
#include "bee2/core/word.h"
|
19
|
|
#include "bee2/crypto/belt.h"
|
20
|
|
#include "bee2/crypto/brng.h"
|
21
|
|
|
22
|
|
/*
|
23
|
|
*******************************************************************************
|
24
|
|
Ускорители: быстрые операции над блоками brng
|
25
|
|
*******************************************************************************
|
26
|
|
*/
|
27
|
|
|
28
|
1
|
static void brngBlockNeg(octet dest[32], const octet src[32])
|
29
|
|
{
|
30
|
1
|
register size_t i = W_OF_O(32);
|
31
|
1
|
while (i--)
|
32
|
1
|
((word*)dest)[i] = ~((const word*)src)[i];
|
33
|
|
}
|
34
|
|
|
35
|
1
|
static void brngBlockXor2(octet dest[32], const octet src[32])
|
36
|
|
{
|
37
|
1
|
register size_t i = W_OF_O(32);
|
38
|
1
|
while (i--)
|
39
|
1
|
((word*)dest)[i] ^= ((const word*)src)[i];
|
40
|
|
}
|
41
|
|
|
42
|
1
|
static void brngBlockInc(octet block[32])
|
43
|
|
{
|
44
|
1
|
register size_t i = 0;
|
45
|
1
|
word* w = (word*)block;
|
46
|
|
do
|
47
|
|
{
|
48
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
49
|
|
w[i] = wordRev(w[i]);
|
50
|
|
++w[i];
|
51
|
|
w[i] = wordRev(w[i]);
|
52
|
|
#else
|
53
|
1
|
++w[i];
|
54
|
|
#endif
|
55
|
|
}
|
56
|
1
|
while (w[i] == 0 && i++ < W_OF_O(32));
|
57
|
1
|
i = 0;
|
58
|
|
}
|
59
|
|
|
60
|
|
/*
|
61
|
|
*******************************************************************************
|
62
|
|
Генерация в режиме CTR
|
63
|
|
|
64
|
|
В brng_ctr_st::state_ex размещаются два beltHash-состояния:
|
65
|
|
- вспомогательное состояние;
|
66
|
|
- состояние beltHash(key ||....).
|
67
|
|
*******************************************************************************
|
68
|
|
*/
|
69
|
|
typedef struct
|
70
|
|
{
|
71
|
|
octet s[32]; /*< переменная s */
|
72
|
|
octet r[32]; /*< переменная r */
|
73
|
|
octet block[32]; /*< блок выходных данных */
|
74
|
|
size_t reserved; /*< резерв выходных октетов */
|
75
|
|
octet state_ex[]; /*< [2 beltHash_keep()] хэш-состояния */
|
76
|
|
} brng_ctr_st;
|
77
|
|
|
78
|
1
|
size_t brngCTR_keep()
|
79
|
|
{
|
80
|
1
|
return sizeof(brng_ctr_st) + 2 * beltHash_keep();
|
81
|
|
}
|
82
|
|
|
83
|
1
|
void brngCTRStart(void* state, const octet key[32], const octet iv[32])
|
84
|
|
{
|
85
|
1
|
brng_ctr_st* s = (brng_ctr_st*)state;
|
86
|
1
|
ASSERT(memIsDisjoint2(s, brngCTR_keep(), key, 32));
|
87
|
1
|
ASSERT(iv == 0 || memIsDisjoint2(s, brngCTR_keep(), iv, 32));
|
88
|
|
// обработать key
|
89
|
1
|
beltHashStart(s->state_ex + beltHash_keep());
|
90
|
1
|
beltHashStepH(key, 32, s->state_ex + beltHash_keep());
|
91
|
|
// сохранить iv
|
92
|
1
|
if (iv)
|
93
|
1
|
memCopy(s->s, iv, 32);
|
94
|
|
else
|
95
|
1
|
memSetZero(s->s, 32);
|
96
|
|
// r <- ~s
|
97
|
1
|
brngBlockNeg(s->r, s->s);
|
98
|
|
// нет выходных данных
|
99
|
1
|
s->reserved = 0;
|
100
|
|
}
|
101
|
|
|
102
|
1
|
void brngCTRStepR(void* buf, size_t count, void* state)
|
103
|
|
{
|
104
|
1
|
brng_ctr_st* s = (brng_ctr_st*)state;
|
105
|
1
|
ASSERT(memIsDisjoint2(buf, count, s, brngCTR_keep()));
|
106
|
|
// есть резерв данных?
|
107
|
1
|
if (s->reserved)
|
108
|
|
{
|
109
|
1
|
if (s->reserved >= count)
|
110
|
|
{
|
111
|
0
|
memCopy(buf, s->block + 32 - s->reserved, count);
|
112
|
0
|
s->reserved -= count;
|
113
|
0
|
return;
|
114
|
|
}
|
115
|
1
|
memCopy(buf, s->block + 32 - s->reserved, s->reserved);
|
116
|
1
|
count -= s->reserved;
|
117
|
1
|
buf = (octet*)buf + s->reserved;
|
118
|
1
|
s->reserved = 0;
|
119
|
|
}
|
120
|
|
// цикл по полным блокам
|
121
|
1
|
while (count >= 32)
|
122
|
|
{
|
123
|
|
// Y_t <- belt-hash(key || s || X_t || r)
|
124
|
1
|
memCopy(s->state_ex, s->state_ex + beltHash_keep(), beltHash_keep());
|
125
|
1
|
beltHashStepH(s->s, 32, s->state_ex);
|
126
|
1
|
beltHashStepH(buf, 32, s->state_ex);
|
127
|
1
|
beltHashStepH(s->r, 32, s->state_ex);
|
128
|
1
|
beltHashStepG(buf, s->state_ex);
|
129
|
|
// next
|
130
|
1
|
brngBlockInc(s->s);
|
131
|
1
|
brngBlockXor2(s->r, buf);
|
132
|
1
|
buf = (octet*)buf + 32;
|
133
|
1
|
count -= 32;
|
134
|
|
}
|
135
|
|
// неполный блок?
|
136
|
1
|
if (count)
|
137
|
|
{
|
138
|
|
// block <- beltHash(key || s || zero_pad(X_t) || r)
|
139
|
1
|
memSetZero(s->block + count, 32 - count);
|
140
|
1
|
memCopy(s->state_ex, s->state_ex + beltHash_keep(), beltHash_keep());
|
141
|
1
|
beltHashStepH(s->s, 32, s->state_ex);
|
142
|
1
|
beltHashStepH(buf, count, s->state_ex);
|
143
|
1
|
beltHashStepH(s->block + count, 32 - count, s->state_ex);
|
144
|
1
|
beltHashStepH(s->r, 32, s->state_ex);
|
145
|
1
|
beltHashStepG(s->block, s->state_ex);
|
146
|
|
// Y_t <- left(block)
|
147
|
1
|
memCopy(buf, s->block, count);
|
148
|
|
// next
|
149
|
1
|
brngBlockInc(s->s);
|
150
|
1
|
brngBlockXor2(s->r, s->block);
|
151
|
1
|
s->reserved = 32 - count;
|
152
|
|
}
|
153
|
|
}
|
154
|
|
|
155
|
1
|
void brngCTRStepG(octet iv[32], void* state)
|
156
|
|
{
|
157
|
1
|
brng_ctr_st* s = (brng_ctr_st*)state;
|
158
|
1
|
ASSERT(memIsDisjoint2(s, brngCTR_keep(), iv, 32));
|
159
|
1
|
memCopy(iv, s->s, 32);
|
160
|
|
}
|
161
|
|
|
162
|
1
|
err_t brngCTRRand(void* buf, size_t count, const octet key[32], octet iv[32])
|
163
|
|
{
|
164
|
|
void* state;
|
165
|
|
// проверить входные данные
|
166
|
1
|
if (!memIsValid(key, 32) ||
|
167
|
1
|
!memIsValid(iv, 32) ||
|
168
|
1
|
!memIsValid(buf, count))
|
169
|
0
|
return ERR_BAD_INPUT;
|
170
|
|
// создать состояние
|
171
|
1
|
state = blobCreate(brngCTR_keep());
|
172
|
1
|
if (state == 0)
|
173
|
0
|
return ERR_OUTOFMEMORY;
|
174
|
|
// сгенерировать данные
|
175
|
1
|
brngCTRStart(state, key, iv);
|
176
|
1
|
brngCTRStepR(buf, count, state);
|
177
|
1
|
brngCTRStepG(iv, state);
|
178
|
|
// завершить
|
179
|
1
|
blobClose(state);
|
180
|
1
|
return ERR_OK;
|
181
|
|
}
|
182
|
|
|
183
|
|
/*
|
184
|
|
*******************************************************************************
|
185
|
|
Генерация в режиме HMAC
|
186
|
|
|
187
|
|
В brng_hmac_st::state_ex размещаются два beltHMAC-состояния:
|
188
|
|
- вспомогательное состояние;
|
189
|
|
- состояние beltHMAC(key, ...).
|
190
|
|
|
191
|
|
\remark Учитывается инкрементальность beltHMAC
|
192
|
|
*******************************************************************************
|
193
|
|
*/
|
194
|
|
typedef struct
|
195
|
|
{
|
196
|
|
const octet* iv; /*< указатель на синхропосылку */
|
197
|
|
octet iv_buf[64]; /*< синхропосылка (если укладывается) */
|
198
|
|
size_t iv_len; /*< длина синхропосылки в октетах */
|
199
|
|
octet r[32]; /*< переменная r */
|
200
|
|
octet block[32]; /*< блок выходных данных */
|
201
|
|
size_t reserved; /*< резерв выходных октетов */
|
202
|
|
octet state_ex[]; /*< [2 * beltHMAC_keep()] hmac-состояния */
|
203
|
|
} brng_hmac_st;
|
204
|
|
|
205
|
1
|
size_t brngHMAC_keep()
|
206
|
|
{
|
207
|
1
|
return sizeof(brng_hmac_st) + 2 * beltHMAC_keep();
|
208
|
|
}
|
209
|
|
|
210
|
1
|
void brngHMACStart(void* state, const octet key[], size_t key_len,
|
211
|
|
const octet iv[], size_t iv_len)
|
212
|
|
{
|
213
|
1
|
brng_hmac_st* s = (brng_hmac_st*)state;
|
214
|
1
|
ASSERT(memIsDisjoint2(s, brngHMAC_keep(), key, key_len));
|
215
|
1
|
ASSERT(memIsDisjoint2(s, brngHMAC_keep(), iv, iv_len));
|
216
|
|
// запомнить iv
|
217
|
1
|
if ((s->iv_len = iv_len) <= 64)
|
218
|
|
{
|
219
|
1
|
memCopy(s->iv_buf, iv, iv_len);
|
220
|
1
|
s->iv = s->iv_buf;
|
221
|
|
}
|
222
|
|
else
|
223
|
1
|
s->iv = iv;
|
224
|
|
// обработать key
|
225
|
1
|
beltHMACStart(s->state_ex + beltHMAC_keep(), key, key_len);
|
226
|
|
// r <- beltHMAC(key, iv)
|
227
|
1
|
memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep());
|
228
|
1
|
beltHMACStepA(iv, iv_len, s->state_ex);
|
229
|
1
|
beltHMACStepG(s->r, s->state_ex);
|
230
|
|
// нет выходных данных
|
231
|
1
|
s->reserved = 0;
|
232
|
|
}
|
233
|
|
|
234
|
1
|
void brngHMACStepR(void* buf, size_t count, void* state)
|
235
|
|
{
|
236
|
1
|
brng_hmac_st* s = (brng_hmac_st*)state;
|
237
|
1
|
ASSERT(memIsDisjoint2(buf, count, s, brngHMAC_keep()));
|
238
|
|
// есть резерв данных?
|
239
|
1
|
if (s->reserved)
|
240
|
|
{
|
241
|
1
|
if (s->reserved >= count)
|
242
|
|
{
|
243
|
1
|
memCopy(buf, s->block + 32 - s->reserved, count);
|
244
|
1
|
s->reserved -= count;
|
245
|
1
|
return;
|
246
|
|
}
|
247
|
0
|
memCopy(buf, s->block + 32 - s->reserved, s->reserved);
|
248
|
0
|
count -= s->reserved;
|
249
|
0
|
buf = (octet*)buf + s->reserved;
|
250
|
0
|
s->reserved = 0;
|
251
|
|
}
|
252
|
|
// цикл по полным блокам
|
253
|
1
|
while (count >= 32)
|
254
|
|
{
|
255
|
|
// r <- beltHMAC(key, r)
|
256
|
1
|
memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep());
|
257
|
1
|
beltHMACStepA(s->r, 32, s->state_ex);
|
258
|
1
|
beltHMACStepG(s->r, s->state_ex);
|
259
|
|
// Y_t <- beltHMAC(key, r || iv)
|
260
|
1
|
beltHMACStepA(s->iv, s->iv_len, s->state_ex);
|
261
|
1
|
beltHMACStepG(buf, s->state_ex);
|
262
|
|
// next
|
263
|
1
|
buf = (octet*)buf + 32;
|
264
|
1
|
count -= 32;
|
265
|
|
}
|
266
|
|
// неполный блок?
|
267
|
1
|
if (count)
|
268
|
|
{
|
269
|
|
// r <- beltHMAC(key, r)
|
270
|
1
|
memCopy(s->state_ex, s->state_ex + beltHMAC_keep(), beltHMAC_keep());
|
271
|
1
|
beltHMACStepA(s->r, 32, s->state_ex);
|
272
|
1
|
beltHMACStepG(s->r, s->state_ex);
|
273
|
|
// Y_t <- left(beltHMAC(key, r || iv))
|
274
|
1
|
beltHMACStepA(s->iv, s->iv_len, s->state_ex);
|
275
|
1
|
beltHMACStepG(s->block, s->state_ex);
|
276
|
1
|
memCopy(buf, s->block, count);
|
277
|
|
// next
|
278
|
1
|
s->reserved = 32 - count;
|
279
|
|
}
|
280
|
|
}
|
281
|
|
|
282
|
1
|
err_t brngHMACRand(void* buf, size_t count, const octet key[], size_t key_len,
|
283
|
|
const octet iv[], size_t iv_len)
|
284
|
|
{
|
285
|
|
void* state;
|
286
|
|
// проверить входные данные
|
287
|
1
|
if (!memIsValid(key, key_len) ||
|
288
|
1
|
!memIsValid(iv, iv_len) ||
|
289
|
1
|
!memIsValid(buf, count) ||
|
290
|
1
|
!memIsDisjoint2(buf, count, iv, iv_len))
|
291
|
0
|
return ERR_BAD_INPUT;
|
292
|
|
// создать состояние
|
293
|
1
|
state = blobCreate(brngHMAC_keep());
|
294
|
1
|
if (state == 0)
|
295
|
0
|
return ERR_OUTOFMEMORY;
|
296
|
|
// сгенерировать данные
|
297
|
1
|
brngHMACStart(state, key, key_len, iv, iv_len);
|
298
|
1
|
brngHMACStepR(buf, count, state);
|
299
|
|
// завершить
|
300
|
1
|
blobClose(state);
|
301
|
1
|
return ERR_OK;
|
302
|
|
}
|