1/*
2 * MD4 (RFC-1320) message digest.
3 * Modified from MD5 code by Andrey Panin <pazke@donpac.ru>
4 *
5 * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
6 * the public domain. There's absolutely no warranty.
7 *
8 * This differs from Colin Plumb's older public domain implementation in
9 * that no 32-bit integer data type is required, there's no compile-time
10 * endianness configuration, and the function prototypes match OpenSSL's.
11 * The primary goals are portability and ease of use.
12 *
13 * This implementation is meant to be fast, but not as fast as possible.
14 * Some known optimizations are not included to reduce source code size
15 * and avoid compile-time configuration.
16 */
17
18#include "md4.h"
19
20#include <string.h>
21
22QT_BEGIN_NAMESPACE
23
24/*
25 * The basic MD4 functions.
26 */
27#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
28#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
29#define H(x, y, z) ((x) ^ (y) ^ (z))
30
31/*
32 * The MD4 transformation for all four rounds.
33 */
34#define STEP(f, a, b, c, d, x, s) \
35 (a) += f((b), (c), (d)) + (x); \
36 (a) = ((a) << (s)) | ((a) >> (32 - (s)))
37
38
39/*
40 * SET reads 4 input bytes in little-endian byte order and stores them
41 * in a properly aligned word in host byte order.
42 *
43 * The check for little-endian architectures which tolerate unaligned
44 * memory accesses is just an optimization. Nothing will break if it
45 * doesn't work.
46 */
47#if defined(__i386__) || defined(__x86_64__)
48#define SET(n) \
49 (*(const quint32 *)&ptr[(n) * 4])
50#define GET(n) \
51 SET(n)
52#else
53#define SET(n) \
54 (ctx->block[(n)] = \
55 (quint32)ptr[(n) * 4] | \
56 ((quint32)ptr[(n) * 4 + 1] << 8) | \
57 ((quint32)ptr[(n) * 4 + 2] << 16) | \
58 ((quint32)ptr[(n) * 4 + 3] << 24))
59#define GET(n) \
60 (ctx->block[(n)])
61#endif
62
63/*
64 * This processes one or more 64-byte data blocks, but does NOT update
65 * the bit counters. There're no alignment requirements.
66 */
67static const unsigned char *body(struct md4_context *ctx, const unsigned char *data, size_t size)
68{
69 const unsigned char *ptr;
70 quint32 a, b, c, d;
71 quint32 saved_a, saved_b, saved_c, saved_d;
72
73 ptr = data;
74
75 a = ctx->a;
76 b = ctx->b;
77 c = ctx->c;
78 d = ctx->d;
79
80 do {
81 saved_a = a;
82 saved_b = b;
83 saved_c = c;
84 saved_d = d;
85
86/* Round 1 */
87 STEP(F, a, b, c, d, SET( 0), 3);
88 STEP(F, d, a, b, c, SET( 1), 7);
89 STEP(F, c, d, a, b, SET( 2), 11);
90 STEP(F, b, c, d, a, SET( 3), 19);
91
92 STEP(F, a, b, c, d, SET( 4), 3);
93 STEP(F, d, a, b, c, SET( 5), 7);
94 STEP(F, c, d, a, b, SET( 6), 11);
95 STEP(F, b, c, d, a, SET( 7), 19);
96
97 STEP(F, a, b, c, d, SET( 8), 3);
98 STEP(F, d, a, b, c, SET( 9), 7);
99 STEP(F, c, d, a, b, SET(10), 11);
100 STEP(F, b, c, d, a, SET(11), 19);
101
102 STEP(F, a, b, c, d, SET(12), 3);
103 STEP(F, d, a, b, c, SET(13), 7);
104 STEP(F, c, d, a, b, SET(14), 11);
105 STEP(F, b, c, d, a, SET(15), 19);
106/* Round 2 */
107 STEP(G, a, b, c, d, GET( 0) + 0x5A827999, 3);
108 STEP(G, d, a, b, c, GET( 4) + 0x5A827999, 5);
109 STEP(G, c, d, a, b, GET( 8) + 0x5A827999, 9);
110 STEP(G, b, c, d, a, GET(12) + 0x5A827999, 13);
111
112 STEP(G, a, b, c, d, GET( 1) + 0x5A827999, 3);
113 STEP(G, d, a, b, c, GET( 5) + 0x5A827999, 5);
114 STEP(G, c, d, a, b, GET( 9) + 0x5A827999, 9);
115 STEP(G, b, c, d, a, GET(13) + 0x5A827999, 13);
116
117 STEP(G, a, b, c, d, GET( 2) + 0x5A827999, 3);
118 STEP(G, d, a, b, c, GET( 6) + 0x5A827999, 5);
119 STEP(G, c, d, a, b, GET(10) + 0x5A827999, 9);
120 STEP(G, b, c, d, a, GET(14) + 0x5A827999, 13);
121
122 STEP(G, a, b, c, d, GET( 3) + 0x5A827999, 3);
123 STEP(G, d, a, b, c, GET( 7) + 0x5A827999, 5);
124 STEP(G, c, d, a, b, GET(11) + 0x5A827999, 9);
125 STEP(G, b, c, d, a, GET(15) + 0x5A827999, 13);
126/* Round 3 */
127 STEP(H, a, b, c, d, GET( 0) + 0x6ED9EBA1, 3);
128 STEP(H, d, a, b, c, GET( 8) + 0x6ED9EBA1, 9);
129 STEP(H, c, d, a, b, GET( 4) + 0x6ED9EBA1, 11);
130 STEP(H, b, c, d, a, GET(12) + 0x6ED9EBA1, 15);
131
132 STEP(H, a, b, c, d, GET( 2) + 0x6ED9EBA1, 3);
133 STEP(H, d, a, b, c, GET(10) + 0x6ED9EBA1, 9);
134 STEP(H, c, d, a, b, GET( 6) + 0x6ED9EBA1, 11);
135 STEP(H, b, c, d, a, GET(14) + 0x6ED9EBA1, 15);
136
137 STEP(H, a, b, c, d, GET( 1) + 0x6ED9EBA1, 3);
138 STEP(H, d, a, b, c, GET( 9) + 0x6ED9EBA1, 9);
139 STEP(H, c, d, a, b, GET( 5) + 0x6ED9EBA1, 11);
140 STEP(H, b, c, d, a, GET(13) + 0x6ED9EBA1, 15);
141
142 STEP(H, a, b, c, d, GET( 3) + 0x6ED9EBA1, 3);
143 STEP(H, d, a, b, c, GET(11) + 0x6ED9EBA1, 9);
144 STEP(H, c, d, a, b, GET( 7) + 0x6ED9EBA1, 11);
145 STEP(H, b, c, d, a, GET(15) + 0x6ED9EBA1, 15);
146
147 a += saved_a;
148 b += saved_b;
149 c += saved_c;
150 d += saved_d;
151
152 ptr += 64;
153 } while (size -= 64);
154
155 ctx->a = a;
156 ctx->b = b;
157 ctx->c = c;
158 ctx->d = d;
159
160 return ptr;
161}
162
163static void md4_init(struct md4_context *ctx)
164{
165 ctx->a = 0x67452301;
166 ctx->b = 0xefcdab89;
167 ctx->c = 0x98badcfe;
168 ctx->d = 0x10325476;
169
170 ctx->lo = 0;
171 ctx->hi = 0;
172}
173
174static void md4_update(struct md4_context *ctx, const unsigned char *data, size_t size)
175{
176 /* @UNSAFE */
177 quint32 saved_lo;
178 unsigned long used, free;
179
180 saved_lo = ctx->lo;
181 if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
182 ctx->hi++;
183 ctx->hi += (quint32)(size >> 29);
184
185 used = saved_lo & 0x3f;
186
187 if (used) {
188 free = 64 - used;
189
190 if (size < free) {
191 memcpy(&ctx->buffer[used], data, size);
192 return;
193 }
194
195 memcpy(&ctx->buffer[used], data, free);
196 data = (const unsigned char *) data + free;
197 size -= free;
198 body(ctx, ctx->buffer, 64);
199 }
200
201 if (size >= 64) {
202 data = body(ctx, data, size & ~(unsigned long)0x3f);
203 size &= 0x3f;
204 }
205
206 memcpy(ctx->buffer, data, size);
207}
208
209static void md4_final(struct md4_context *ctx, unsigned char result[MD4_RESULTLEN])
210{
211 /* @UNSAFE */
212 unsigned long used, free;
213
214 used = ctx->lo & 0x3f;
215
216 ctx->buffer[used++] = 0x80;
217
218 free = 64 - used;
219
220 if (free < 8) {
221 memset(&ctx->buffer[used], 0, free);
222 body(ctx, ctx->buffer, 64);
223 used = 0;
224 free = 64;
225 }
226
227 memset(&ctx->buffer[used], 0, free - 8);
228
229 ctx->lo <<= 3;
230 ctx->buffer[56] = ctx->lo;
231 ctx->buffer[57] = ctx->lo >> 8;
232 ctx->buffer[58] = ctx->lo >> 16;
233 ctx->buffer[59] = ctx->lo >> 24;
234 ctx->buffer[60] = ctx->hi;
235 ctx->buffer[61] = ctx->hi >> 8;
236 ctx->buffer[62] = ctx->hi >> 16;
237 ctx->buffer[63] = ctx->hi >> 24;
238
239 body(ctx, ctx->buffer, 64);
240
241 result[0] = ctx->a;
242 result[1] = ctx->a >> 8;
243 result[2] = ctx->a >> 16;
244 result[3] = ctx->a >> 24;
245 result[4] = ctx->b;
246 result[5] = ctx->b >> 8;
247 result[6] = ctx->b >> 16;
248 result[7] = ctx->b >> 24;
249 result[8] = ctx->c;
250 result[9] = ctx->c >> 8;
251 result[10] = ctx->c >> 16;
252 result[11] = ctx->c >> 24;
253 result[12] = ctx->d;
254 result[13] = ctx->d >> 8;
255 result[14] = ctx->d >> 16;
256 result[15] = ctx->d >> 24;
257
258 memset(ctx, 0, sizeof(*ctx));
259}
260
261#undef F
262#undef G
263#undef H
264
265QT_END_NAMESPACE
266