Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/examples/hash/mdc2.c
34889 views
1
/*
2
* Copyright (C) 2021 - This file is part of libecc project
3
*
4
* Authors:
5
* Ryad BENADJILA <[email protected]>
6
* Arnaud EBALARD <[email protected]>
7
*
8
* This software is licensed under a dual BSD and GPL v2 license.
9
* See LICENSE file at the root folder of the project.
10
*/
11
#include "mdc2.h"
12
13
/* Include DES helpers */
14
#include "tdes.h"
15
16
ATTRIBUTE_WARN_UNUSED_RET int mdc2_set_padding_type(mdc2_context *ctx,
17
padding_type p)
18
{
19
int ret;
20
21
MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
22
23
/* We cannot change the padding type after the first update */
24
MUST_HAVE((ctx->mdc2_total == 0), ret, err);
25
26
if((p != ISOIEC10118_TYPE1) && (p != ISOIEC10118_TYPE2)){
27
ret = -1;
28
goto err;
29
}
30
31
ctx->padding = p;
32
33
ret = 0;
34
35
err:
36
return ret;
37
}
38
39
/* MDC-2 core processing. Returns 0 on success, -1 on error. */
40
ATTRIBUTE_WARN_UNUSED_RET static inline int mdc2_process(mdc2_context *ctx,
41
const u8 data[MDC2_BLOCK_SIZE])
42
{
43
int ret;
44
unsigned int j;
45
u8 V[8], W[8];
46
u8 *A, *B;
47
des_context des_ctx;
48
49
/* Get the current internal state in A and B */
50
A = (u8*)&(ctx->mdc2_state[0]);
51
B = (u8*)&(ctx->mdc2_state[8]);
52
53
A[0] = (u8)((A[0] & 0x9f) | 0x40);
54
B[0] = (u8)((B[0] & 0x9f) | 0x20);
55
/* Set odd parity */
56
for(j = 0; j < 8; j++){
57
A[j] = odd_parity[A[j]];
58
B[j] = odd_parity[B[j]];
59
}
60
/* Compute V_i = M_i + E(M_i, A_i) */
61
ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);
62
ret = des_set_key(&des_ctx, A, DES_ENCRYPTION); EG(ret, err);
63
ret = des(&des_ctx, &data[0], V); EG(ret, err);
64
for(j = 0; j < 8; j++){
65
V[j] = (V[j] ^ data[j]);
66
}
67
/* Compute W_i = M_i + E(M_i, B_i) */
68
ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);
69
ret = des_set_key(&des_ctx, B, DES_ENCRYPTION); EG(ret, err);
70
ret = des(&des_ctx, &data[0], W); EG(ret, err);
71
for(j = 0; j < 8; j++){
72
W[j] = (W[j] ^ data[j]);
73
}
74
/* Cross the results */
75
/* In A */
76
ret = local_memcpy(&A[0], &V[0], 4); EG(ret, err);
77
ret = local_memcpy(&A[4], &W[4], 4); EG(ret, err);
78
/* In B */
79
ret = local_memcpy(&B[0], &W[0], 4); EG(ret, err);
80
ret = local_memcpy(&B[4], &V[4], 4); EG(ret, err);
81
82
err:
83
return ret;
84
}
85
86
/* Init hash function. Returns 0 on success, -1 on error. */
87
ATTRIBUTE_WARN_UNUSED_RET int mdc2_init(mdc2_context *ctx)
88
{
89
int ret;
90
91
MUST_HAVE((ctx != NULL), ret, err);
92
93
/* Sanity check on size */
94
MUST_HAVE((MDC2_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);
95
96
ctx->mdc2_total = 0;
97
/* Initialize A1 */
98
ret = local_memset(&(ctx->mdc2_state[0]), 0x52, 8); EG(ret, err);
99
/* Initialize B1 */
100
ret = local_memset(&(ctx->mdc2_state[8]), 0x25, 8); EG(ret, err);
101
/* Initialize default padding type */
102
ctx->padding = ISOIEC10118_TYPE1;
103
104
/* Tell that we are initialized */
105
ctx->magic = MDC2_HASH_MAGIC;
106
107
ret = 0;
108
109
err:
110
return ret;
111
}
112
113
ATTRIBUTE_WARN_UNUSED_RET int mdc2_update(mdc2_context *ctx, const u8 *input, u32 ilen)
114
{
115
const u8 *data_ptr = input;
116
u32 remain_ilen = ilen;
117
u16 fill;
118
u8 left;
119
int ret;
120
121
MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
122
MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
123
124
/* Nothing to process, return */
125
if (ilen == 0) {
126
ret = 0;
127
goto err;
128
}
129
130
/* Get what's left in our local buffer */
131
left = (ctx->mdc2_total & 0xF);
132
fill = (u16)(MDC2_BLOCK_SIZE - left);
133
134
ctx->mdc2_total += ilen;
135
136
if ((left > 0) && (remain_ilen >= fill)) {
137
/* Copy data at the end of the buffer */
138
ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, fill); EG(ret, err);
139
ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
140
data_ptr += fill;
141
remain_ilen -= fill;
142
left = 0;
143
}
144
145
while (remain_ilen >= MDC2_BLOCK_SIZE) {
146
ret = mdc2_process(ctx, data_ptr); EG(ret, err);
147
data_ptr += MDC2_BLOCK_SIZE;
148
remain_ilen -= MDC2_BLOCK_SIZE;
149
}
150
151
if (remain_ilen > 0) {
152
ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, remain_ilen); EG(ret, err);
153
}
154
155
ret = 0;
156
157
err:
158
return ret;
159
}
160
161
/* Finalize. Returns 0 on success, -1 on error.*/
162
ATTRIBUTE_WARN_UNUSED_RET int mdc2_final(mdc2_context *ctx, u8 output[MDC2_DIGEST_SIZE])
163
{
164
int ret;
165
unsigned int i;
166
u8 pad_byte;
167
168
MUST_HAVE((output != NULL), ret, err);
169
MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
170
171
if(ctx->padding == ISOIEC10118_TYPE1){
172
/* "Padding method 1" in ISO-IEC-10118 */
173
/* This is our final step, so we proceed with the padding: the last block
174
* is padded with zeroes.
175
*/
176
pad_byte = 0x00;
177
if((ctx->mdc2_total % MDC2_BLOCK_SIZE) != 0){
178
for(i = (ctx->mdc2_total % MDC2_BLOCK_SIZE); i < MDC2_BLOCK_SIZE; i++){
179
ctx->mdc2_buffer[i] = pad_byte;
180
}
181
/* And process the block */
182
ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
183
}
184
}
185
else if(ctx->padding == ISOIEC10118_TYPE2){
186
/* "Padding method 2" in ISO-IEC-10118 */
187
/* This is our final step, so we proceed with the padding: the last block
188
* is appended 0x80 and then padded with zeroes.
189
*/
190
ctx->mdc2_buffer[(ctx->mdc2_total % MDC2_BLOCK_SIZE)] = 0x80;
191
pad_byte = 0x00;
192
for(i = ((unsigned int)(ctx->mdc2_total % MDC2_BLOCK_SIZE) + 1); i < MDC2_BLOCK_SIZE; i++){
193
ctx->mdc2_buffer[i] = pad_byte;
194
}
195
/* And process the block */
196
ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
197
}
198
else{
199
/* Unkown padding */
200
ret = -1;
201
goto err;
202
}
203
204
/* Output the hash result */
205
ret = local_memcpy(output, ctx->mdc2_state, MDC2_DIGEST_SIZE); EG(ret, err);
206
207
/* Tell that we are uninitialized */
208
ctx->magic = WORD(0);
209
210
ret = 0;
211
212
err:
213
return ret;
214
}
215
216
217
/*
218
* Scattered version performing init/update/finalize on a vector of buffers
219
* 'inputs' with the length of each buffer passed via 'ilens'. The function
220
* loops on pointers in 'inputs' until it finds a NULL pointer. The function
221
* returns 0 on success, -1 on error.
222
*/
223
ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered(const u8 **inputs, const u32 *ilens,
224
u8 output[MDC2_DIGEST_SIZE], padding_type p)
225
{
226
mdc2_context ctx;
227
int ret, pos = 0;
228
229
MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
230
231
ret = mdc2_init(&ctx); EG(ret, err);
232
233
ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);
234
235
while (inputs[pos] != NULL) {
236
ret = mdc2_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
237
pos += 1;
238
}
239
240
ret = mdc2_final(&ctx, output);
241
242
err:
243
return ret;
244
}
245
246
/*
247
* Scattered version performing init/update/finalize on a vector of buffers
248
* 'inputs' with the length of each buffer passed via 'ilens'. The function
249
* loops on pointers in 'inputs' until it finds a NULL pointer. The function
250
* returns 0 on success, -1 on error.
251
*/
252
ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding1(const u8 **inputs, const u32 *ilens,
253
u8 output[MDC2_DIGEST_SIZE])
254
{
255
return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE1);
256
}
257
258
/*
259
* Scattered version performing init/update/finalize on a vector of buffers
260
* 'inputs' with the length of each buffer passed via 'ilens'. The function
261
* loops on pointers in 'inputs' until it finds a NULL pointer. The function
262
* returns 0 on success, -1 on error.
263
*/
264
ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding2(const u8 **inputs, const u32 *ilens,
265
u8 output[MDC2_DIGEST_SIZE])
266
{
267
return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE2);
268
}
269
270
/*
271
* Single call version performing init/update/final on given input.
272
* Returns 0 on success, -1 on error.
273
*/
274
ATTRIBUTE_WARN_UNUSED_RET int mdc2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE], padding_type p)
275
{
276
mdc2_context ctx;
277
int ret;
278
279
ret = mdc2_init(&ctx); EG(ret, err);
280
ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);
281
ret = mdc2_update(&ctx, input, ilen); EG(ret, err);
282
ret = mdc2_final(&ctx, output);
283
284
err:
285
return ret;
286
}
287
288
289
/*
290
* Single call version performing init/update/final on given input.
291
* Returns 0 on success, -1 on error.
292
*/
293
ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding1(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])
294
{
295
return mdc2(input, ilen, output, ISOIEC10118_TYPE1);
296
}
297
298
/*
299
* Single call version performing init/update/final on given input.
300
* Returns 0 on success, -1 on error.
301
*/
302
ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])
303
{
304
return mdc2(input, ilen, output, ISOIEC10118_TYPE2);
305
}
306
307