1
|
|
/*
|
2
|
|
*******************************************************************************
|
3
|
|
\file belt_che.c
|
4
|
|
\brief STB 34.101.31 (belt): CHE (Ctr-Hash-Encrypt) authenticated encryption
|
5
|
|
\project bee2 [cryptographic library]
|
6
|
|
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
|
7
|
|
\created 2020.03.20
|
8
|
|
\version 2020.04.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/crypto/belt.h"
|
19
|
|
#include "bee2/math/ww.h"
|
20
|
|
#include "belt_lcl.h"
|
21
|
|
|
22
|
|
/*
|
23
|
|
*******************************************************************************
|
24
|
|
Аутентифицированное шифрование данных (CHE)
|
25
|
|
|
26
|
|
\remark Режим get-then-continue реализован, но пока не рекомендован
|
27
|
|
(вплоть до завершения оценки надежности).
|
28
|
|
*******************************************************************************
|
29
|
|
*/
|
30
|
|
|
31
|
|
typedef struct
|
32
|
|
{
|
33
|
|
u32 key[8]; /*< форматированный ключ */
|
34
|
|
u32 s[4]; /*< переменная s */
|
35
|
|
word r[W_OF_B(128)]; /*< переменная r */
|
36
|
|
word t[W_OF_B(128)]; /*< переменная t */
|
37
|
|
word t1[W_OF_B(128)]; /*< копия t/имитовставка */
|
38
|
|
word len[W_OF_B(128)]; /*< обработано открытых || критических данных */
|
39
|
|
octet block[16]; /*< блок аутентифицируемых данных */
|
40
|
|
octet block1[16]; /*< блок гаммы */
|
41
|
|
size_t filled; /*< накоплено октетов в block */
|
42
|
|
size_t reserved; /*< резерв октетов гаммы */
|
43
|
|
octet stack[]; /*< стек умножения */
|
44
|
|
} belt_che_st;
|
45
|
|
|
46
|
1
|
size_t beltCHE_keep()
|
47
|
|
{
|
48
|
1
|
return sizeof(belt_che_st) + beltPolyMul_deep();
|
49
|
|
}
|
50
|
|
|
51
|
1
|
void beltCHEStart(void* state, const octet key[], size_t len,
|
52
|
|
const octet iv[16])
|
53
|
|
{
|
54
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
55
|
1
|
ASSERT(memIsDisjoint2(iv, 16, state, beltCHE_keep()));
|
56
|
|
// разобрать key и iv
|
57
|
1
|
beltKeyExpand2(st->key, key, len);
|
58
|
1
|
beltBlockCopy(st->r, iv);
|
59
|
1
|
beltBlockEncr((octet*)st->r, st->key);
|
60
|
1
|
u32From(st->s, st->r, 16);
|
61
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
62
|
|
beltBlockRevW(st->r);
|
63
|
|
#endif
|
64
|
|
// подготовить t
|
65
|
1
|
wwFrom(st->t, beltH(), 16);
|
66
|
|
// обнулить счетчики
|
67
|
1
|
memSetZero(st->len, sizeof(st->len));
|
68
|
1
|
st->reserved = 0;
|
69
|
1
|
st->filled = 0;
|
70
|
|
}
|
71
|
|
|
72
|
1
|
void beltCHEStepE(void* buf, size_t count, void* state)
|
73
|
|
{
|
74
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
75
|
1
|
ASSERT(memIsDisjoint2(buf, count, state, beltCHE_keep()));
|
76
|
|
// есть резерв гаммы?
|
77
|
1
|
if (st->reserved)
|
78
|
|
{
|
79
|
1
|
if (st->reserved >= count)
|
80
|
|
{
|
81
|
1
|
memXor2(buf, st->block1 + 16 - st->reserved, count);
|
82
|
1
|
st->reserved -= count;
|
83
|
1
|
return;
|
84
|
|
}
|
85
|
0
|
memXor2(buf, st->block1 + 16 - st->reserved, st->reserved);
|
86
|
0
|
count -= st->reserved;
|
87
|
0
|
buf = (octet*)buf + st->reserved;
|
88
|
0
|
st->reserved = 0;
|
89
|
|
}
|
90
|
|
// цикл по полным блокам
|
91
|
1
|
while (count >= 16)
|
92
|
|
{
|
93
|
1
|
beltBlockMulC(st->s), st->s[0] ^= 0x00000001;
|
94
|
1
|
beltBlockCopy(st->block1, st->s);
|
95
|
1
|
beltBlockEncr2((u32*)st->block1, st->key);
|
96
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
97
|
|
beltBlockRevU32(st->block1);
|
98
|
|
#endif
|
99
|
1
|
beltBlockXor2(buf, st->block1);
|
100
|
1
|
buf = (octet*)buf + 16;
|
101
|
1
|
count -= 16;
|
102
|
|
}
|
103
|
|
// неполный блок?
|
104
|
1
|
if (count)
|
105
|
|
{
|
106
|
1
|
beltBlockMulC(st->s), st->s[0] ^= 0x00000001;
|
107
|
1
|
beltBlockCopy(st->block1, st->s);
|
108
|
1
|
beltBlockEncr2((u32*)st->block1, st->key);
|
109
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
110
|
|
beltBlockRevU32(st->block1);
|
111
|
|
#endif
|
112
|
1
|
memXor2(buf, st->block1, count);
|
113
|
1
|
st->reserved = 16 - count;
|
114
|
|
}
|
115
|
|
}
|
116
|
|
|
117
|
1
|
void beltCHEStepI(const void* buf, size_t count, void* state)
|
118
|
|
{
|
119
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
120
|
1
|
ASSERT(memIsDisjoint2(buf, count, state, beltCHE_keep()));
|
121
|
|
// критические данные не обрабатывались?
|
122
|
1
|
ASSERT(count == 0 || beltHalfBlockIsZero(st->len + W_OF_B(64)));
|
123
|
|
// обновить длину
|
124
|
1
|
beltHalfBlockAddBitSizeW(st->len, count);
|
125
|
|
// есть накопленные данные?
|
126
|
1
|
if (st->filled)
|
127
|
|
{
|
128
|
1
|
if (count < 16 - st->filled)
|
129
|
|
{
|
130
|
0
|
memCopy(st->block + st->filled, buf, count);
|
131
|
0
|
st->filled += count;
|
132
|
0
|
return;
|
133
|
|
}
|
134
|
1
|
memCopy(st->block + st->filled, buf, 16 - st->filled);
|
135
|
1
|
count -= 16 - st->filled;
|
136
|
1
|
buf = (const octet*)buf + 16 - st->filled;
|
137
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
138
|
|
beltBlockRevW(st->block);
|
139
|
|
#endif
|
140
|
1
|
beltBlockXor2(st->t, st->block);
|
141
|
1
|
beltPolyMul(st->t, st->t, st->r, st->stack);
|
142
|
1
|
st->filled = 0;
|
143
|
|
}
|
144
|
|
// цикл по полным блокам
|
145
|
1
|
while (count >= 16)
|
146
|
|
{
|
147
|
1
|
beltBlockCopy(st->block, buf);
|
148
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
149
|
|
beltBlockRevW(st->block);
|
150
|
|
#endif
|
151
|
1
|
beltBlockXor2(st->t, st->block);
|
152
|
1
|
beltPolyMul(st->t, st->t, st->r, st->stack);
|
153
|
1
|
buf = (const octet*)buf + 16;
|
154
|
1
|
count -= 16;
|
155
|
|
}
|
156
|
|
// неполный блок?
|
157
|
1
|
if (count)
|
158
|
1
|
memCopy(st->block, buf, st->filled = count);
|
159
|
|
}
|
160
|
|
|
161
|
1
|
void beltCHEStepA(const void* buf, size_t count, void* state)
|
162
|
|
{
|
163
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
164
|
1
|
ASSERT(memIsDisjoint2(buf, count, state, beltCHE_keep()));
|
165
|
|
// первый непустой фрагмент критических данных?
|
166
|
|
// есть необработанные открытые данные?
|
167
|
1
|
if (count && beltHalfBlockIsZero(st->len + W_OF_B(64)) && st->filled)
|
168
|
|
{
|
169
|
1
|
memSetZero(st->block + st->filled, 16 - st->filled);
|
170
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
171
|
|
beltBlockRevW(st->block);
|
172
|
|
#endif
|
173
|
1
|
beltBlockXor2(st->t, st->block);
|
174
|
1
|
beltPolyMul(st->t, st->t, st->r, st->stack);
|
175
|
1
|
st->filled = 0;
|
176
|
|
}
|
177
|
|
// обновить длину
|
178
|
1
|
beltHalfBlockAddBitSizeW(st->len + W_OF_B(64), count);
|
179
|
|
// есть накопленные данные?
|
180
|
1
|
if (st->filled)
|
181
|
|
{
|
182
|
1
|
if (count < 16 - st->filled)
|
183
|
|
{
|
184
|
1
|
memCopy(st->block + st->filled, buf, count);
|
185
|
1
|
st->filled += count;
|
186
|
1
|
return;
|
187
|
|
}
|
188
|
0
|
memCopy(st->block + st->filled, buf, 16 - st->filled);
|
189
|
0
|
count -= 16 - st->filled;
|
190
|
0
|
buf = (const octet*)buf + 16 - st->filled;
|
191
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
192
|
|
beltBlockRevW(st->block);
|
193
|
|
#endif
|
194
|
0
|
beltBlockXor2(st->t, st->block);
|
195
|
0
|
beltPolyMul(st->t, st->t, st->r, st->stack);
|
196
|
0
|
st->filled = 0;
|
197
|
|
}
|
198
|
|
// цикл по полным блокам
|
199
|
1
|
while (count >= 16)
|
200
|
|
{
|
201
|
1
|
beltBlockCopy(st->block, buf);
|
202
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
203
|
|
beltBlockRevW(st->block);
|
204
|
|
#endif
|
205
|
1
|
beltBlockXor2(st->t, st->block);
|
206
|
1
|
beltPolyMul(st->t, st->t, st->r, st->stack);
|
207
|
1
|
buf = (const octet*)buf + 16;
|
208
|
1
|
count -= 16;
|
209
|
|
}
|
210
|
|
// неполный блок?
|
211
|
1
|
if (count)
|
212
|
1
|
memCopy(st->block, buf, st->filled = count);
|
213
|
|
}
|
214
|
|
|
215
|
1
|
void beltCHEStepD(void* buf, size_t count, void* state)
|
216
|
|
{
|
217
|
1
|
beltCHEStepE(buf, count, state);
|
218
|
|
}
|
219
|
|
|
220
|
1
|
static void beltCHEStepG_internal(void* state)
|
221
|
|
{
|
222
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
223
|
1
|
ASSERT(memIsValid(state, beltCHE_keep()));
|
224
|
|
// создать копию t и завершить обработку данных
|
225
|
1
|
if (st->filled)
|
226
|
|
{
|
227
|
1
|
memSetZero(st->block + st->filled, 16 - st->filled);
|
228
|
1
|
wwFrom(st->t1, st->block, 16);
|
229
|
1
|
beltBlockXor2(st->t1, st->t);
|
230
|
1
|
beltPolyMul(st->t1, st->t1, st->r, st->stack);
|
231
|
|
}
|
232
|
|
else
|
233
|
0
|
memCopy(st->t1, st->t, 16);
|
234
|
|
// обработать блок длины
|
235
|
1
|
beltBlockXor2(st->t1, st->len);
|
236
|
1
|
beltPolyMul(st->t1, st->t1, st->r, st->stack);
|
237
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
238
|
|
beltBlockRevW(st->t1);
|
239
|
|
#endif
|
240
|
1
|
beltBlockEncr((octet*)st->t1, st->key);
|
241
|
|
}
|
242
|
|
|
243
|
1
|
void beltCHEStepG(octet mac[8], void* state)
|
244
|
|
{
|
245
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
246
|
1
|
ASSERT(memIsValid(mac, 8));
|
247
|
1
|
beltCHEStepG_internal(state);
|
248
|
1
|
memCopy(mac, st->t1, 8);
|
249
|
|
}
|
250
|
|
|
251
|
1
|
bool_t beltCHEStepV(const octet mac[8], void* state)
|
252
|
|
{
|
253
|
1
|
belt_che_st* st = (belt_che_st*)state;
|
254
|
1
|
ASSERT(memIsValid(mac, 8));
|
255
|
1
|
beltCHEStepG_internal(state);
|
256
|
1
|
return memEq(mac, st->t1, 8);
|
257
|
|
}
|
258
|
|
|
259
|
1
|
err_t beltCHEWrap(void* dest, octet mac[8], const void* src1, size_t count1,
|
260
|
|
const void* src2, size_t count2, const octet key[], size_t len,
|
261
|
|
const octet iv[16])
|
262
|
|
{
|
263
|
|
void* state;
|
264
|
|
// проверить входные данные
|
265
|
1
|
if (len != 16 && len != 24 && len != 32 ||
|
266
|
1
|
!memIsValid(src1, count1) ||
|
267
|
1
|
!memIsValid(src2, count2) ||
|
268
|
1
|
!memIsValid(key, len) ||
|
269
|
1
|
!memIsValid(iv, 16) ||
|
270
|
1
|
!memIsValid(dest, count1) ||
|
271
|
1
|
!memIsValid(mac, 8))
|
272
|
0
|
return ERR_BAD_INPUT;
|
273
|
|
// создать состояние
|
274
|
1
|
state = blobCreate(beltCHE_keep());
|
275
|
1
|
if (state == 0)
|
276
|
0
|
return ERR_OUTOFMEMORY;
|
277
|
|
// установить защиту (I перед E из-за разрешенного пересечения src2 и dest)
|
278
|
1
|
beltCHEStart(state, key, len, iv);
|
279
|
1
|
beltCHEStepI(src2, count2, state);
|
280
|
1
|
memMove(dest, src1, count1);
|
281
|
1
|
beltCHEStepE(dest, count1, state);
|
282
|
1
|
beltCHEStepA(dest, count1, state);
|
283
|
1
|
beltCHEStepG(mac, state);
|
284
|
|
// завершить
|
285
|
1
|
blobClose(state);
|
286
|
1
|
return ERR_OK;
|
287
|
|
}
|
288
|
|
|
289
|
1
|
err_t beltCHEUnwrap(void* dest, const void* src1, size_t count1,
|
290
|
|
const void* src2, size_t count2, const octet mac[8], const octet key[],
|
291
|
|
size_t len, const octet iv[16])
|
292
|
|
{
|
293
|
|
void* state;
|
294
|
|
// проверить входные данные
|
295
|
1
|
if (len != 16 && len != 24 && len != 32 ||
|
296
|
1
|
!memIsValid(src1, count1) ||
|
297
|
1
|
!memIsValid(src2, count2) ||
|
298
|
1
|
!memIsValid(mac, 8) ||
|
299
|
1
|
!memIsValid(key, len) ||
|
300
|
1
|
!memIsValid(iv, 16) ||
|
301
|
1
|
!memIsValid(dest, count1))
|
302
|
0
|
return ERR_BAD_INPUT;
|
303
|
|
// создать состояние
|
304
|
1
|
state = blobCreate(beltDWP_keep());
|
305
|
1
|
if (state == 0)
|
306
|
0
|
return ERR_OUTOFMEMORY;
|
307
|
|
// снять защиту
|
308
|
1
|
beltCHEStart(state, key, len, iv);
|
309
|
1
|
beltCHEStepI(src2, count2, state);
|
310
|
1
|
beltCHEStepA(src1, count1, state);
|
311
|
1
|
if (!beltCHEStepV(mac, state))
|
312
|
|
{
|
313
|
0
|
blobClose(state);
|
314
|
0
|
return ERR_BAD_MAC;
|
315
|
|
}
|
316
|
1
|
memMove(dest, src1, count1);
|
317
|
1
|
beltCHEStepD(dest, count1, state);
|
318
|
|
// завершить
|
319
|
1
|
blobClose(state);
|
320
|
1
|
return ERR_OK;
|
321
|
|
}
|