xref: /PHP-8.1/ext/hash/hash_md.c (revision 01b3fc03)
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