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 0
		memSetZero(st->block + st->filled, 16 - st->filled);
170
#if (OCTET_ORDER == BIG_ENDIAN)
171
		beltBlockRevW(st->block);
172
#endif
173 0
		beltBlockXor2(st->t, st->block);
174 0
		beltPolyMul(st->t, st->t, st->r, st->stack);
175 0
		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 1
		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
}

Read our documentation on viewing source code .

Loading