Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/examples/hash/md4.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 "md4.h"
12
13
/* All the inner MD-4 operations */
14
static const u32 C1_MD4[13] = {
15
0, 4, 8, 12, 0, 1, 2, 3, 3, 7, 11, 19, 0
16
};
17
static const u32 C2_MD4[13] = {
18
0, 1, 2, 3, 0, 4, 8, 12, 3, 5, 9, 13, 0x5a827999
19
};
20
static const u32 C3_MD4[13] = {
21
0, 2, 1, 3, 0, 8, 4, 12, 3, 9, 11, 15, 0x6ed9eba1
22
};
23
24
#define F_MD4(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
25
#define G_MD4(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
26
#define H_MD4(x, y, z) ((x) ^ (y) ^ (z))
27
28
/* SHA-2 core processing. Returns 0 on success, -1 on error. */
29
ATTRIBUTE_WARN_UNUSED_RET static inline int md4_process(md4_context *ctx,
30
const u8 data[MD4_BLOCK_SIZE])
31
{
32
u32 A, B, C, D;
33
u32 W[16];
34
u32 idx;
35
int ret;
36
unsigned int i;
37
38
MUST_HAVE((data != NULL), ret, err);
39
MD4_HASH_CHECK_INITIALIZED(ctx, ret, err);
40
41
/* Init our inner variables */
42
A = ctx->md4_state[0];
43
B = ctx->md4_state[1];
44
C = ctx->md4_state[2];
45
D = ctx->md4_state[3];
46
47
/* Load data */
48
for (i = 0; i < 16; i++) {
49
GET_UINT32_LE(W[i], data, (4 * i));
50
}
51
/* Proceed with the compression */
52
for (i = 0; i < 4; i++) {
53
idx = (C1_MD4[i] + C1_MD4[4]);
54
A = ROTL_MD4((A + F_MD4(B, C, D) + W[idx] + C1_MD4[12]), C1_MD4[8]);
55
idx = (C1_MD4[i] + C1_MD4[5]);
56
D = ROTL_MD4((D + F_MD4(A, B, C) + W[idx] + C1_MD4[12]), C1_MD4[9]);
57
idx = (C1_MD4[i] + C1_MD4[6]);
58
C = ROTL_MD4((C + F_MD4(D, A, B) + W[idx] + C1_MD4[12]), C1_MD4[10]);
59
idx = (C1_MD4[i] + C1_MD4[7]);
60
B = ROTL_MD4((B + F_MD4(C, D, A) + W[idx] + C1_MD4[12]), C1_MD4[11]);
61
}
62
for (i = 0; i < 4; i++) {
63
idx = (C2_MD4[i] + C2_MD4[4]);
64
A = ROTL_MD4((A + G_MD4(B, C, D) + W[idx] + C2_MD4[12]), C2_MD4[8]);
65
idx = (C2_MD4[i] + C2_MD4[5]);
66
D = ROTL_MD4((D + G_MD4(A, B, C) + W[idx] + C2_MD4[12]), C2_MD4[9]);
67
idx = (C2_MD4[i] + C2_MD4[6]);
68
C = ROTL_MD4((C + G_MD4(D, A, B) + W[idx] + C2_MD4[12]), C2_MD4[10]);
69
idx = (C2_MD4[i] + C2_MD4[7]);
70
B = ROTL_MD4((B + G_MD4(C, D, A) + W[idx] + C2_MD4[12]), C2_MD4[11]);
71
}
72
for (i = 0; i < 4; i++) {
73
idx = (C3_MD4[i] + C3_MD4[4]);
74
A = ROTL_MD4((A + H_MD4(B, C, D) + W[idx] + C3_MD4[12]), C3_MD4[8]);
75
idx = (C3_MD4[i] + C3_MD4[5]);
76
D = ROTL_MD4((D + H_MD4(A, B, C) + W[idx] + C3_MD4[12]), C3_MD4[9]);
77
idx = (C3_MD4[i] + C3_MD4[6]);
78
C = ROTL_MD4((C + H_MD4(D, A, B) + W[idx] + C3_MD4[12]), C3_MD4[10]);
79
idx = (C3_MD4[i] + C3_MD4[7]);
80
B = ROTL_MD4((B + H_MD4(C, D, A) + W[idx] + C3_MD4[12]), C3_MD4[11]);
81
}
82
83
/* Update state */
84
ctx->md4_state[0] += A;
85
ctx->md4_state[1] += B;
86
ctx->md4_state[2] += C;
87
ctx->md4_state[3] += D;
88
89
ret = 0;
90
91
err:
92
return ret;
93
}
94
95
/* Init hash function. Returns 0 on success, -1 on error. */
96
ATTRIBUTE_WARN_UNUSED_RET int md4_init(md4_context *ctx)
97
{
98
int ret;
99
100
MUST_HAVE((ctx != NULL), ret, err);
101
102
/* Sanity check on size */
103
MUST_HAVE((MD4_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);
104
105
ctx->md4_total = 0;
106
ctx->md4_state[0] = 0x67452301;
107
ctx->md4_state[1] = 0xEFCDAB89;
108
ctx->md4_state[2] = 0x98BADCFE;
109
ctx->md4_state[3] = 0x10325476;
110
111
/* Tell that we are initialized */
112
ctx->magic = MD4_HASH_MAGIC;
113
114
ret = 0;
115
116
err:
117
return ret;
118
}
119
120
ATTRIBUTE_WARN_UNUSED_RET int md4_update(md4_context *ctx, const u8 *input, u32 ilen)
121
{
122
const u8 *data_ptr = input;
123
u32 remain_ilen = ilen;
124
u16 fill;
125
u8 left;
126
int ret;
127
128
MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
129
MD4_HASH_CHECK_INITIALIZED(ctx, ret, err);
130
131
/* Nothing to process, return */
132
if (ilen == 0) {
133
ret = 0;
134
goto err;
135
}
136
137
/* Get what's left in our local buffer */
138
left = (ctx->md4_total & 0x3F);
139
fill = (u16)(MD4_BLOCK_SIZE - left);
140
141
ctx->md4_total += ilen;
142
143
if ((left > 0) && (remain_ilen >= fill)) {
144
/* Copy data at the end of the buffer */
145
ret = local_memcpy(ctx->md4_buffer + left, data_ptr, fill); EG(ret, err);
146
ret = md4_process(ctx, ctx->md4_buffer); EG(ret, err);
147
data_ptr += fill;
148
remain_ilen -= fill;
149
left = 0;
150
}
151
152
while (remain_ilen >= MD4_BLOCK_SIZE) {
153
ret = md4_process(ctx, data_ptr); EG(ret, err);
154
data_ptr += MD4_BLOCK_SIZE;
155
remain_ilen -= MD4_BLOCK_SIZE;
156
}
157
158
if (remain_ilen > 0) {
159
ret = local_memcpy(ctx->md4_buffer + left, data_ptr, remain_ilen); EG(ret, err);
160
}
161
162
ret = 0;
163
164
err:
165
return ret;
166
}
167
168
/* Finalize. Returns 0 on success, -1 on error.*/
169
ATTRIBUTE_WARN_UNUSED_RET int md4_final(md4_context *ctx, u8 output[MD4_DIGEST_SIZE])
170
{
171
unsigned int block_present = 0;
172
u8 last_padded_block[2 * MD4_BLOCK_SIZE];
173
int ret;
174
175
MUST_HAVE((output != NULL), ret, err);
176
MD4_HASH_CHECK_INITIALIZED(ctx, ret, err);
177
178
/* Fill in our last block with zeroes */
179
ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
180
181
/* This is our final step, so we proceed with the padding */
182
block_present = ctx->md4_total % MD4_BLOCK_SIZE;
183
if (block_present != 0) {
184
/* Copy what's left in our temporary context buffer */
185
ret = local_memcpy(last_padded_block, ctx->md4_buffer,
186
block_present); EG(ret, err);
187
}
188
189
/* Put the 0x80 byte, beginning of padding */
190
last_padded_block[block_present] = 0x80;
191
192
/* Handle possible additional block */
193
if (block_present > (MD4_BLOCK_SIZE - 1 - sizeof(u64))) {
194
/* We need an additional block */
195
PUT_UINT64_LE(8 * ctx->md4_total, last_padded_block,
196
(2 * MD4_BLOCK_SIZE) - sizeof(u64));
197
ret = md4_process(ctx, last_padded_block); EG(ret, err);
198
ret = md4_process(ctx, last_padded_block + MD4_BLOCK_SIZE); EG(ret, err);
199
} else {
200
/* We do not need an additional block */
201
PUT_UINT64_LE(8 * ctx->md4_total, last_padded_block,
202
MD4_BLOCK_SIZE - sizeof(u64));
203
ret = md4_process(ctx, last_padded_block); EG(ret, err);
204
}
205
206
/* Output the hash result */
207
PUT_UINT32_LE(ctx->md4_state[0], output, 0);
208
PUT_UINT32_LE(ctx->md4_state[1], output, 4);
209
PUT_UINT32_LE(ctx->md4_state[2], output, 8);
210
PUT_UINT32_LE(ctx->md4_state[3], output, 12);
211
212
/* Tell that we are uninitialized */
213
ctx->magic = WORD(0);
214
215
ret = 0;
216
217
err:
218
return ret;
219
}
220
221
222
/*
223
* Scattered version performing init/update/finalize on a vector of buffers
224
* 'inputs' with the length of each buffer passed via 'ilens'. The function
225
* loops on pointers in 'inputs' until it finds a NULL pointer. The function
226
* returns 0 on success, -1 on error.
227
*/
228
ATTRIBUTE_WARN_UNUSED_RET int md4_scattered(const u8 **inputs, const u32 *ilens,
229
u8 output[MD4_DIGEST_SIZE])
230
{
231
md4_context ctx;
232
int ret, pos = 0;
233
234
MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
235
236
ret = md4_init(&ctx); EG(ret, err);
237
238
while (inputs[pos] != NULL) {
239
ret = md4_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
240
pos += 1;
241
}
242
243
ret = md4_final(&ctx, output);
244
245
err:
246
return ret;
247
}
248
249
/*
250
* Single call version performing init/update/final on given input.
251
* Returns 0 on success, -1 on error.
252
*/
253
ATTRIBUTE_WARN_UNUSED_RET int md4(const u8 *input, u32 ilen, u8 output[MD4_DIGEST_SIZE])
254
{
255
md4_context ctx;
256
int ret;
257
258
ret = md4_init(&ctx); EG(ret, err);
259
ret = md4_update(&ctx, input, ilen); EG(ret, err);
260
ret = md4_final(&ctx, output);
261
262
err:
263
return ret;
264
}
265
266