1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Taken from: ext/standard/md5.c |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "php_hash.h"
18 #include "php_hash_md.h"
19
20 const php_hash_ops php_hash_md5_ops = {
21 "md5",
22 (php_hash_init_func_t) PHP_MD5InitArgs,
23 (php_hash_update_func_t) PHP_MD5Update,
24 (php_hash_final_func_t) PHP_MD5Final,
25 php_hash_copy,
26 php_hash_serialize,
27 php_hash_unserialize,
28 PHP_MD5_SPEC,
29 16,
30 64,
31 sizeof(PHP_MD5_CTX),
32 1
33 };
34
35 const php_hash_ops php_hash_md4_ops = {
36 "md4",
37 (php_hash_init_func_t) PHP_MD4InitArgs,
38 (php_hash_update_func_t) PHP_MD4Update,
39 (php_hash_final_func_t) PHP_MD4Final,
40 php_hash_copy,
41 php_hash_serialize,
42 php_hash_unserialize,
43 PHP_MD4_SPEC,
44 16,
45 64,
46 sizeof(PHP_MD4_CTX),
47 1
48 };
49
50 static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv);
51
52 const php_hash_ops php_hash_md2_ops = {
53 "md2",
54 (php_hash_init_func_t) PHP_MD2InitArgs,
55 (php_hash_update_func_t) PHP_MD2Update,
56 (php_hash_final_func_t) PHP_MD2Final,
57 php_hash_copy,
58 php_hash_serialize,
59 php_md2_unserialize,
60 PHP_MD2_SPEC,
61 16,
62 16,
63 sizeof(PHP_MD2_CTX),
64 1
65 };
66
67 /* MD common stuff */
68
69 static const unsigned char PADDING[64] =
70 {
71 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
74 };
75
76 /* {{{ Encode
77 Encodes input (uint32_t) into output (unsigned char). Assumes len is
78 a multiple of 4.
79 */
Encode(unsigned char * output,uint32_t * input,unsigned int len)80 static void Encode(unsigned char *output, uint32_t *input, unsigned int len)
81 {
82 unsigned int i, j;
83
84 for (i = 0, j = 0; j < len; i++, j += 4) {
85 output[j] = (unsigned char) (input[i] & 0xff);
86 output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
87 output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
88 output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
89 }
90 }
91 /* }}} */
92
93 /* {{{ Decode
94 Decodes input (unsigned char) into output (uint32_t). Assumes len is
95 a multiple of 4.
96 */
Decode(uint32_t * output,const unsigned char * input,unsigned int len)97 static void Decode(uint32_t *output, const unsigned char *input, unsigned int len)
98 {
99 unsigned int i, j;
100
101 for (i = 0, j = 0; j < len; i++, j += 4)
102 output[i] = ((uint32_t) input[j]) | (((uint32_t) input[j + 1]) << 8) |
103 (((uint32_t) input[j + 2]) << 16) | (((uint32_t) input[j + 3]) << 24);
104 }
105 /* }}} */
106
107 /* MD4 */
108
109 #define MD4_F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
110 #define MD4_G(x,y,z) (((x) & ((y) | (z))) | ((y) & (z)))
111 #define MD4_H(x,y,z) ((x) ^ (y) ^ (z))
112
113 #define ROTL32(s,v) (((v) << (s)) | ((v) >> (32 - (s))))
114
115 #define MD4_R1(a,b,c,d,k,s) a = ROTL32(s, a + MD4_F(b,c,d) + x[k])
116 #define MD4_R2(a,b,c,d,k,s) a = ROTL32(s, a + MD4_G(b,c,d) + x[k] + 0x5A827999)
117 #define MD4_R3(a,b,c,d,k,s) a = ROTL32(s, a + MD4_H(b,c,d) + x[k] + 0x6ED9EBA1)
118
MD4Transform(uint32_t state[4],const unsigned char block[64])119 static void MD4Transform(uint32_t state[4], const unsigned char block[64])
120 {
121 uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
122
123 Decode(x, block, 64);
124
125 /* Round 1 */
126 MD4_R1(a,b,c,d, 0, 3);
127 MD4_R1(d,a,b,c, 1, 7);
128 MD4_R1(c,d,a,b, 2,11);
129 MD4_R1(b,c,d,a, 3,19);
130 MD4_R1(a,b,c,d, 4, 3);
131 MD4_R1(d,a,b,c, 5, 7);
132 MD4_R1(c,d,a,b, 6,11);
133 MD4_R1(b,c,d,a, 7,19);
134 MD4_R1(a,b,c,d, 8, 3);
135 MD4_R1(d,a,b,c, 9, 7);
136 MD4_R1(c,d,a,b,10,11);
137 MD4_R1(b,c,d,a,11,19);
138 MD4_R1(a,b,c,d,12, 3);
139 MD4_R1(d,a,b,c,13, 7);
140 MD4_R1(c,d,a,b,14,11);
141 MD4_R1(b,c,d,a,15,19);
142
143 /* Round 2 */
144 MD4_R2(a,b,c,d, 0, 3);
145 MD4_R2(d,a,b,c, 4, 5);
146 MD4_R2(c,d,a,b, 8, 9);
147 MD4_R2(b,c,d,a,12,13);
148 MD4_R2(a,b,c,d, 1, 3);
149 MD4_R2(d,a,b,c, 5, 5);
150 MD4_R2(c,d,a,b, 9, 9);
151 MD4_R2(b,c,d,a,13,13);
152 MD4_R2(a,b,c,d, 2, 3);
153 MD4_R2(d,a,b,c, 6, 5);
154 MD4_R2(c,d,a,b,10, 9);
155 MD4_R2(b,c,d,a,14,13);
156 MD4_R2(a,b,c,d, 3, 3);
157 MD4_R2(d,a,b,c, 7, 5);
158 MD4_R2(c,d,a,b,11, 9);
159 MD4_R2(b,c,d,a,15,13);
160
161 /* Round 3 */
162 MD4_R3(a,b,c,d, 0, 3);
163 MD4_R3(d,a,b,c, 8, 9);
164 MD4_R3(c,d,a,b, 4,11);
165 MD4_R3(b,c,d,a,12,15);
166 MD4_R3(a,b,c,d, 2, 3);
167 MD4_R3(d,a,b,c,10, 9);
168 MD4_R3(c,d,a,b, 6,11);
169 MD4_R3(b,c,d,a,14,15);
170 MD4_R3(a,b,c,d, 1, 3);
171 MD4_R3(d,a,b,c, 9, 9);
172 MD4_R3(c,d,a,b, 5,11);
173 MD4_R3(b,c,d,a,13,15);
174 MD4_R3(a,b,c,d, 3, 3);
175 MD4_R3(d,a,b,c,11, 9);
176 MD4_R3(c,d,a,b, 7,11);
177 MD4_R3(b,c,d,a,15,15);
178
179 state[0] += a;
180 state[1] += b;
181 state[2] += c;
182 state[3] += d;
183 }
184
185 /* {{{ PHP_MD4InitArgs
186 * MD4 initialization. Begins an MD4 operation, writing a new context.
187 */
PHP_MD4InitArgs(PHP_MD4_CTX * context,ZEND_ATTRIBUTE_UNUSED HashTable * args)188 PHP_HASH_API void PHP_MD4InitArgs(PHP_MD4_CTX * context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
189 {
190 context->count[0] = context->count[1] = 0;
191 /* Load magic initialization constants.
192 */
193 context->state[0] = 0x67452301;
194 context->state[1] = 0xefcdab89;
195 context->state[2] = 0x98badcfe;
196 context->state[3] = 0x10325476;
197 }
198 /* }}} */
199
200 /* {{{ PHP_MD4Update
201 MD4 block update operation. Continues an MD4 message-digest
202 operation, processing another message block, and updating the
203 context.
204 */
PHP_MD4Update(PHP_MD4_CTX * context,const unsigned char * input,size_t inputLen)205 PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *input, size_t inputLen)
206 {
207 unsigned int index, partLen;
208 size_t i;
209
210 /* Compute number of bytes mod 64 */
211 index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
212
213 /* Update number of bits */
214 if ((context->count[0] += ((uint32_t) inputLen << 3))
215 < ((uint32_t) inputLen << 3))
216 context->count[1]++;
217 context->count[1] += (uint32_t) (inputLen >> 29);
218
219 partLen = 64 - index;
220
221 /* Transform as many times as possible.
222 */
223 if (inputLen >= partLen) {
224 memcpy((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
225 MD4Transform(context->state, context->buffer);
226
227 for (i = partLen; i + 63 < inputLen; i += 64) {
228 MD4Transform(context->state, &input[i]);
229 }
230
231 index = 0;
232 } else {
233 i = 0;
234 }
235
236 /* Buffer remaining input */
237 memcpy((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], inputLen - i);
238 }
239 /* }}} */
240
241 /* {{{ PHP_MD4Final
242 MD4 finalization. Ends an MD4 message-digest operation, writing
243 the message digest and zeroizing the context.
244 */
PHP_MD4Final(unsigned char digest[16],PHP_MD4_CTX * context)245 PHP_HASH_API void PHP_MD4Final(unsigned char digest[16], PHP_MD4_CTX * context)
246 {
247 unsigned char bits[8];
248 unsigned int index, padLen;
249
250 /* Save number of bits */
251 Encode(bits, context->count, 8);
252
253 /* Pad out to 56 mod 64.
254 */
255 index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
256 padLen = (index < 56) ? (56 - index) : (120 - index);
257 PHP_MD4Update(context, PADDING, padLen);
258
259 /* Append length (before padding) */
260 PHP_MD4Update(context, bits, 8);
261
262 /* Store state in digest */
263 Encode(digest, context->state, 16);
264
265 /* Zeroize sensitive information.
266 */
267 ZEND_SECURE_ZERO((unsigned char*) context, sizeof(*context));
268 }
269 /* }}} */
270
271 /* MD2 */
272
273 static const unsigned char MD2_S[256] = {
274 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,
275 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,
276 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,
277 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,
278 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,
279 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,
280 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,
281 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,
282 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,
283 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
284 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,
285 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,
286 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
287 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,
288 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
289 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
290
PHP_MD2InitArgs(PHP_MD2_CTX * context,ZEND_ATTRIBUTE_UNUSED HashTable * args)291 PHP_HASH_API void PHP_MD2InitArgs(PHP_MD2_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
292 {
293 memset(context, 0, sizeof(PHP_MD2_CTX));
294 }
295
MD2_Transform(PHP_MD2_CTX * context,const unsigned char * block)296 static void MD2_Transform(PHP_MD2_CTX *context, const unsigned char *block)
297 {
298 unsigned char i,j,t = 0;
299
300 for(i = 0; i < 16; i++) {
301 context->state[16+i] = block[i];
302 context->state[32+i] = (context->state[16+i] ^ context->state[i]);
303 }
304
305 for(i = 0; i < 18; i++) {
306 for(j = 0; j < 48; j++) {
307 t = context->state[j] = context->state[j] ^ MD2_S[t];
308 }
309 t += i;
310 }
311
312 /* Update checksum -- must be after transform to avoid fouling up last message block */
313 t = context->checksum[15];
314 for(i = 0; i < 16; i++) {
315 t = context->checksum[i] ^= MD2_S[block[i] ^ t];
316 }
317 }
318
PHP_MD2Update(PHP_MD2_CTX * context,const unsigned char * buf,size_t len)319 PHP_HASH_API void PHP_MD2Update(PHP_MD2_CTX *context, const unsigned char *buf, size_t len)
320 {
321 const unsigned char *p = buf, *e = buf + len;
322
323 if (context->in_buffer) {
324 if (context->in_buffer + len < 16) {
325 /* Not enough for block, just pass into buffer */
326 memcpy(context->buffer + context->in_buffer, p, len);
327 context->in_buffer += (char) len;
328 return;
329 }
330 /* Put buffered data together with inbound for a single block */
331 memcpy(context->buffer + context->in_buffer, p, 16 - context->in_buffer);
332 MD2_Transform(context, context->buffer);
333 p += 16 - context->in_buffer;
334 context->in_buffer = 0;
335 }
336
337 /* Process as many whole blocks as remain */
338 while ((p + 16) <= e) {
339 MD2_Transform(context, p);
340 p += 16;
341 }
342
343 /* Copy remaining data to buffer */
344 if (p < e) {
345 memcpy(context->buffer, p, e - p);
346 context->in_buffer = (char) (e - p);
347 }
348 }
349
PHP_MD2Final(unsigned char output[16],PHP_MD2_CTX * context)350 PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context)
351 {
352 memset(context->buffer + context->in_buffer, 16 - context->in_buffer, 16 - context->in_buffer);
353 MD2_Transform(context, context->buffer);
354 MD2_Transform(context, context->checksum);
355
356 memcpy(output, context->state, 16);
357 }
358
php_md2_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv)359 static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
360 {
361 PHP_MD2_CTX *ctx = (PHP_MD2_CTX *) hash->context;
362 int r = FAILURE;
363 if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
364 && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == SUCCESS
365 && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) {
366 return SUCCESS;
367 } else {
368 return r != SUCCESS ? r : -2000;
369 }
370 }
371