xref: /PHP-8.3/ext/hash/hash_md.c (revision 2b8c0085)
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