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