1
|
|
/*
|
2
|
|
*******************************************************************************
|
3
|
|
\file belt_hmac.c
|
4
|
|
\brief STB 34.101.31 (belt): HMAC message authentication
|
5
|
|
\project bee2 [cryptographic library]
|
6
|
|
\author (C) Sergey Agievich [agievich@{bsu.by|gmail.com}]
|
7
|
|
\created 2012.12.18
|
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/err.h"
|
16
|
|
#include "bee2/core/mem.h"
|
17
|
|
#include "bee2/core/u32.h"
|
18
|
|
#include "bee2/core/util.h"
|
19
|
|
#include "bee2/crypto/belt.h"
|
20
|
|
#include "belt_lcl.h"
|
21
|
|
|
22
|
|
/*
|
23
|
|
*******************************************************************************
|
24
|
|
Ключезависимое хэширование (HMAC)
|
25
|
|
*******************************************************************************
|
26
|
|
*/
|
27
|
|
typedef struct
|
28
|
|
{
|
29
|
|
u32 ls_in[8]; /*< блок [4]len || [4]s внутреннего хэширования */
|
30
|
|
u32 h_in[8]; /*< переменная h внутреннего хэширования */
|
31
|
|
u32 h1_in[8]; /*< копия переменной h внутреннего хэширования */
|
32
|
|
u32 ls_out[8]; /*< блок [4]len || [4]s внешнего хэширования */
|
33
|
|
u32 h_out[8]; /*< переменная h внешнего хэширования */
|
34
|
|
u32 h1_out[8]; /*< копия переменной h внешнего хэширования */
|
35
|
|
u32 s1[4]; /*< копия переменной s */
|
36
|
|
octet block[32]; /*< блок данных */
|
37
|
|
size_t filled; /*< накоплено октетов в блоке */
|
38
|
|
octet stack[]; /*< [beltCompr_deep()] стек beltCompr */
|
39
|
|
} belt_hmac_st;
|
40
|
|
|
41
|
1
|
size_t beltHMAC_keep()
|
42
|
|
{
|
43
|
1
|
return sizeof(belt_hmac_st) + beltCompr_deep();
|
44
|
|
}
|
45
|
|
|
46
|
1
|
void beltHMACStart(void* state, const octet key[], size_t len)
|
47
|
|
{
|
48
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
49
|
1
|
ASSERT(memIsDisjoint2(key, len, state, beltHMAC_keep()));
|
50
|
|
// key <- key || 0
|
51
|
1
|
if (len <= 32)
|
52
|
|
{
|
53
|
1
|
memCopy(st->block, key, len);
|
54
|
1
|
memSetZero(st->block + len, 32 - len);
|
55
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
56
|
|
beltBlockRevU32(st->block);
|
57
|
|
beltBlockRevU32(st->block + 16);
|
58
|
|
#endif
|
59
|
|
}
|
60
|
|
// key <- beltHash(key)
|
61
|
|
else
|
62
|
|
{
|
63
|
1
|
beltBlockSetZero(st->ls_in);
|
64
|
1
|
beltBlockAddBitSizeU32(st->ls_in, len);
|
65
|
1
|
beltBlockSetZero(st->ls_in + 4);
|
66
|
1
|
u32From(st->h_in, beltH(), 32);
|
67
|
1
|
while (len >= 32)
|
68
|
|
{
|
69
|
1
|
beltBlockCopy(st->block, key);
|
70
|
1
|
beltBlockCopy(st->block + 16, key + 16);
|
71
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
72
|
|
beltBlockRevU32(st->block);
|
73
|
|
beltBlockRevU32(st->block + 16);
|
74
|
|
#endif
|
75
|
1
|
beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack);
|
76
|
1
|
key += 32;
|
77
|
1
|
len -= 32;
|
78
|
|
}
|
79
|
1
|
if (len)
|
80
|
|
{
|
81
|
1
|
memCopy(st->block, key, len);
|
82
|
1
|
memSetZero(st->block + len, 32 - len);
|
83
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
84
|
|
beltBlockRevU32(st->block);
|
85
|
|
beltBlockRevU32(st->block + 16);
|
86
|
|
#endif
|
87
|
1
|
beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack);
|
88
|
|
}
|
89
|
1
|
beltCompr(st->h_in, st->ls_in, st->stack);
|
90
|
1
|
beltBlockCopy(st->block, st->h_in);
|
91
|
1
|
beltBlockCopy(st->block + 16, st->h_in + 4);
|
92
|
|
}
|
93
|
|
// сформировать key ^ ipad
|
94
|
1
|
for (len = 0; len < 32; ++len)
|
95
|
1
|
st->block[len] ^= 0x36;
|
96
|
|
// начать внутреннее хэширование
|
97
|
1
|
beltBlockSetZero(st->ls_in);
|
98
|
1
|
beltBlockAddBitSizeU32(st->ls_in, 32);
|
99
|
1
|
beltBlockSetZero(st->ls_in + 4);
|
100
|
1
|
u32From(st->h_in, beltH(), 32);
|
101
|
1
|
beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack);
|
102
|
1
|
st->filled = 0;
|
103
|
|
// сформировать key ^ opad [0x36 ^ 0x5C == 0x6A]
|
104
|
1
|
for (; len--; )
|
105
|
1
|
st->block[len] ^= 0x6A;
|
106
|
|
// начать внешнее хэширование [будет хэшироваться ровно два блока]
|
107
|
1
|
beltBlockSetZero(st->ls_out);
|
108
|
1
|
beltBlockAddBitSizeU32(st->ls_out, 32 * 2);
|
109
|
1
|
beltBlockSetZero(st->ls_out + 4);
|
110
|
1
|
u32From(st->h_out, beltH(), 32);
|
111
|
1
|
beltCompr2(st->ls_out + 4, st->h_out, (u32*)st->block, st->stack);
|
112
|
|
}
|
113
|
|
|
114
|
1
|
void beltHMACStepA(const void* buf, size_t count, void* state)
|
115
|
|
{
|
116
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
117
|
1
|
ASSERT(memIsDisjoint2(buf, count, state, beltHMAC_keep()));
|
118
|
|
// обновить длину
|
119
|
1
|
beltBlockAddBitSizeU32(st->ls_in, count);
|
120
|
|
// есть накопленные данные?
|
121
|
1
|
if (st->filled)
|
122
|
|
{
|
123
|
1
|
if (count < 32 - st->filled)
|
124
|
|
{
|
125
|
1
|
memCopy(st->block + st->filled, buf, count);
|
126
|
1
|
st->filled += count;
|
127
|
1
|
return;
|
128
|
|
}
|
129
|
1
|
memCopy(st->block + st->filled, buf, 32 - st->filled);
|
130
|
1
|
count -= 32 - st->filled;
|
131
|
1
|
buf = (const octet*)buf + 32 - st->filled;
|
132
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
133
|
|
beltBlockRevU32(st->block);
|
134
|
|
beltBlockRevU32(st->block + 16);
|
135
|
|
#endif
|
136
|
1
|
beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack);
|
137
|
1
|
st->filled = 0;
|
138
|
|
}
|
139
|
|
// цикл по полным блокам
|
140
|
1
|
while (count >= 32)
|
141
|
|
{
|
142
|
1
|
beltBlockCopy(st->block, buf);
|
143
|
1
|
beltBlockCopy(st->block + 16, (const octet*)buf + 16);
|
144
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
145
|
|
beltBlockRevU32(st->block);
|
146
|
|
beltBlockRevU32(st->block + 16);
|
147
|
|
#endif
|
148
|
1
|
beltCompr2(st->ls_in + 4, st->h_in, (u32*)st->block, st->stack);
|
149
|
1
|
buf = (const octet*)buf + 32;
|
150
|
1
|
count -= 32;
|
151
|
|
}
|
152
|
|
// неполный блок?
|
153
|
1
|
if (count)
|
154
|
1
|
memCopy(st->block, buf, st->filled = count);
|
155
|
|
}
|
156
|
|
|
157
|
1
|
static void beltHMACStepG_internal(void* state)
|
158
|
|
{
|
159
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
160
|
|
// pre
|
161
|
1
|
ASSERT(memIsValid(state, beltHash_keep()));
|
162
|
|
// создать копии второй части st->ls_in и st->h_in
|
163
|
1
|
beltBlockCopy(st->s1, st->ls_in + 4);
|
164
|
1
|
beltBlockCopy(st->h1_in, st->h_in);
|
165
|
1
|
beltBlockCopy(st->h1_in + 4, st->h_in + 4);
|
166
|
|
// есть необработанные данные?
|
167
|
1
|
if (st->filled)
|
168
|
|
{
|
169
|
1
|
memSetZero(st->block + st->filled, 32 - st->filled);
|
170
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
171
|
|
beltBlockRevU32(st->block);
|
172
|
|
beltBlockRevU32(st->block + 16);
|
173
|
|
#endif
|
174
|
1
|
beltCompr2(st->ls_in + 4, st->h1_in, (u32*)st->block, st->stack);
|
175
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
176
|
|
beltBlockRevU32(st->block + 16);
|
177
|
|
beltBlockRevU32(st->block);
|
178
|
|
#endif
|
179
|
|
}
|
180
|
|
// последний блок внутреннего хэширования
|
181
|
1
|
beltCompr(st->h1_in, st->ls_in, st->stack);
|
182
|
|
// восстановить сохраненную часть st->ls_in
|
183
|
1
|
beltBlockCopy(st->ls_in + 4, st->s1);
|
184
|
|
// создать копии второй части st->ls_out и st->h_out
|
185
|
1
|
beltBlockCopy(st->s1, st->ls_out + 4);
|
186
|
1
|
beltBlockCopy(st->h1_out, st->h_out);
|
187
|
1
|
beltBlockCopy(st->h1_out + 4, st->h_out + 4);
|
188
|
|
// обработать блок st->h1_in
|
189
|
1
|
beltCompr2(st->ls_out + 4, st->h1_out, st->h1_in, st->stack);
|
190
|
|
// последний блок внешнего хэширования
|
191
|
1
|
beltCompr(st->h1_out, st->ls_out, st->stack);
|
192
|
|
// восстановить сохраненную часть st->ls_out
|
193
|
1
|
beltBlockCopy(st->ls_out + 4, st->s1);
|
194
|
|
}
|
195
|
|
|
196
|
1
|
void beltHMACStepG(octet mac[32], void* state)
|
197
|
|
{
|
198
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
199
|
1
|
ASSERT(memIsValid(mac, 32));
|
200
|
1
|
beltHMACStepG_internal(state);
|
201
|
1
|
u32To(mac, 32, st->h1_out);
|
202
|
|
}
|
203
|
|
|
204
|
1
|
void beltHMACStepG2(octet mac[], size_t mac_len, void* state)
|
205
|
|
{
|
206
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
207
|
1
|
ASSERT(mac_len <= 32);
|
208
|
1
|
ASSERT(memIsValid(mac, mac_len));
|
209
|
1
|
beltHMACStepG_internal(state);
|
210
|
1
|
u32To(mac, mac_len, st->h1_out);
|
211
|
|
}
|
212
|
|
|
213
|
1
|
bool_t beltHMACStepV(const octet mac[32], void* state)
|
214
|
|
{
|
215
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
216
|
1
|
ASSERT(memIsValid(mac, 32));
|
217
|
1
|
beltHMACStepG_internal(state);
|
218
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
219
|
|
beltBlockRevU32(st->h1_out);
|
220
|
|
beltBlockRevU32(st->h1_out + 4);
|
221
|
|
#endif
|
222
|
1
|
return memEq(mac, st->h1_out, 32);
|
223
|
|
}
|
224
|
|
|
225
|
1
|
bool_t beltHMACStepV2(const octet mac[], size_t mac_len, void* state)
|
226
|
|
{
|
227
|
1
|
belt_hmac_st* st = (belt_hmac_st*)state;
|
228
|
1
|
ASSERT(mac_len <= 32);
|
229
|
1
|
ASSERT(memIsValid(mac, mac_len));
|
230
|
1
|
beltHMACStepG_internal(state);
|
231
|
|
#if (OCTET_ORDER == BIG_ENDIAN)
|
232
|
|
beltBlockRevU32(st->h1_out);
|
233
|
|
beltBlockRevU32(st->h1_out + 4);
|
234
|
|
#endif
|
235
|
1
|
return memEq(mac, st->h1_out, mac_len);
|
236
|
|
}
|
237
|
|
|
238
|
1
|
err_t beltHMAC(octet mac[32], const void* src, size_t count,
|
239
|
|
const octet key[], size_t len)
|
240
|
|
{
|
241
|
|
void* state;
|
242
|
|
// проверить входные данные
|
243
|
1
|
if (!memIsValid(src, count) ||
|
244
|
1
|
!memIsValid(key, len) ||
|
245
|
1
|
!memIsValid(mac, 32))
|
246
|
0
|
return ERR_BAD_INPUT;
|
247
|
|
// создать состояние
|
248
|
1
|
state = blobCreate(beltHMAC_keep());
|
249
|
1
|
if (state == 0)
|
250
|
0
|
return ERR_OUTOFMEMORY;
|
251
|
|
// выработать имитовставку
|
252
|
1
|
beltHMACStart(state, key, len);
|
253
|
1
|
beltHMACStepA(src, count, state);
|
254
|
1
|
beltHMACStepG(mac, state);
|
255
|
|
// завершить
|
256
|
1
|
blobClose(state);
|
257
|
1
|
return ERR_OK;
|
258
|
|
}
|