xref: /PHP-8.4/ext/hash/hash_snefru.c (revision a60c6ee0)
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   | Authors: Michael Wallner <mike@php.net>                              |
14   |          Sara Golemon <pollita@php.net>                              |
15   +----------------------------------------------------------------------+
16 */
17 
18 #include "php_hash.h"
19 #include "php_hash_snefru.h"
20 #include "php_hash_snefru_tables.h"
21 
22 #define round(L, C, N, SB)	\
23 	SBE = SB[C & 0xff]; \
24 	L ^= SBE; \
25 	N ^= SBE
26 
27 #ifndef DBG_SNEFRU
28 #define DBG_SNEFRU 0
29 #endif
30 
31 #if DBG_SNEFRU
ph(uint32_t h[16])32 void ph(uint32_t h[16])
33 {
34 	int i;
35 	for (i = 0; i < 16; i++)
36 		printf ("%08lx", h[i]); printf("\n");
37 }
38 #endif
39 
Snefru(uint32_t input[16])40 static inline void Snefru(uint32_t input[16])
41 {
42 	static const int shifts[4] = {16, 8, 16, 24};
43 	int b, index, rshift, lshift;
44 	const uint32_t *t0,*t1;
45 	uint32_t SBE,B00,B01,B02,B03,B04,B05,B06,B07,B08,B09,B10,B11,B12,B13,B14,B15;
46 
47 	B00 = input[0];
48 	B01 = input[1];
49 	B02 = input[2];
50 	B03 = input[3];
51 	B04 = input[4];
52 	B05 = input[5];
53 	B06 = input[6];
54 	B07 = input[7];
55 	B08 = input[8];
56 	B09 = input[9];
57 	B10 = input[10];
58 	B11 = input[11];
59 	B12 = input[12];
60 	B13 = input[13];
61 	B14 = input[14];
62 	B15 = input[15];
63 
64 	for (index = 0; index < 8; index++) {
65 		t0 = tables[2*index+0];
66 		t1 = tables[2*index+1];
67 		for (b = 0; b < 4; b++) {
68 			round(B15, B00, B01, t0);
69 			round(B00, B01, B02, t0);
70 			round(B01, B02, B03, t1);
71 			round(B02, B03, B04, t1);
72 			round(B03, B04, B05, t0);
73 			round(B04, B05, B06, t0);
74 			round(B05, B06, B07, t1);
75 			round(B06, B07, B08, t1);
76 			round(B07, B08, B09, t0);
77 			round(B08, B09, B10, t0);
78 			round(B09, B10, B11, t1);
79 			round(B10, B11, B12, t1);
80 			round(B11, B12, B13, t0);
81 			round(B12, B13, B14, t0);
82 			round(B13, B14, B15, t1);
83 			round(B14, B15, B00, t1);
84 
85 			rshift = shifts[b];
86 			lshift = 32-rshift;
87 
88 			B00 = (B00 >> rshift) | (B00 << lshift);
89 			B01 = (B01 >> rshift) | (B01 << lshift);
90 			B02 = (B02 >> rshift) | (B02 << lshift);
91 			B03 = (B03 >> rshift) | (B03 << lshift);
92 			B04 = (B04 >> rshift) | (B04 << lshift);
93 			B05 = (B05 >> rshift) | (B05 << lshift);
94 			B06 = (B06 >> rshift) | (B06 << lshift);
95 			B07 = (B07 >> rshift) | (B07 << lshift);
96 			B08 = (B08 >> rshift) | (B08 << lshift);
97 			B09 = (B09 >> rshift) | (B09 << lshift);
98 			B10 = (B10 >> rshift) | (B10 << lshift);
99 			B11 = (B11 >> rshift) | (B11 << lshift);
100 			B12 = (B12 >> rshift) | (B12 << lshift);
101 			B13 = (B13 >> rshift) | (B13 << lshift);
102 			B14 = (B14 >> rshift) | (B14 << lshift);
103 			B15 = (B15 >> rshift) | (B15 << lshift);
104 		}
105 	}
106 	input[0] ^= B15;
107 	input[1] ^= B14;
108 	input[2] ^= B13;
109 	input[3] ^= B12;
110 	input[4] ^= B11;
111 	input[5] ^= B10;
112 	input[6] ^= B09;
113 	input[7] ^= B08;
114 #if DBG_SNEFRU
115 	ph(input);
116 #endif
117 }
118 
SnefruTransform(PHP_SNEFRU_CTX * context,const unsigned char input[32])119 static inline void SnefruTransform(PHP_SNEFRU_CTX *context, const unsigned char input[32])
120 {
121 	int i, j;
122 
123 	for (i = 0, j = 0; i < 32; i += 4, ++j) {
124 		context->state[8+j] =	((unsigned)input[i] << 24) | ((unsigned)input[i+1] << 16) |
125 								((unsigned)input[i+2] << 8) | (unsigned)input[i+3];
126 	}
127 	Snefru(context->state);
128 	ZEND_SECURE_ZERO(&context->state[8], sizeof(uint32_t) * 8);
129 }
130 
PHP_SNEFRUInit(PHP_SNEFRU_CTX * context,ZEND_ATTRIBUTE_UNUSED HashTable * args)131 PHP_HASH_API void PHP_SNEFRUInit(PHP_SNEFRU_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
132 {
133 	memset(context, 0, sizeof(*context));
134 }
135 
136 static const uint32_t MAX32 = 0xffffffffLU;
137 
PHP_SNEFRUUpdate(PHP_SNEFRU_CTX * context,const unsigned char * input,size_t len)138 PHP_HASH_API void PHP_SNEFRUUpdate(PHP_SNEFRU_CTX *context, const unsigned char *input, size_t len)
139 {
140 	if ((MAX32 - context->count[1]) < (len * 8)) {
141 		context->count[0]++;
142 		context->count[1] = MAX32 - context->count[1];
143 		context->count[1] = ((uint32_t) len * 8) - context->count[1];
144 	} else {
145 		context->count[1] += (uint32_t) len * 8;
146 	}
147 
148 	if (context->length + len < 32) {
149 		memcpy(&context->buffer[context->length], input, len);
150 		context->length += (unsigned char)len;
151 	} else {
152 		size_t i = 0, r = (context->length + len) % 32;
153 
154 		if (context->length) {
155 			i = 32 - context->length;
156 			memcpy(&context->buffer[context->length], input, i);
157 			SnefruTransform(context, context->buffer);
158 		}
159 
160 		for (; i + 32 <= len; i += 32) {
161 			SnefruTransform(context, input + i);
162 		}
163 
164 		memcpy(context->buffer, input + i, r);
165 		ZEND_SECURE_ZERO(&context->buffer[r], 32 - r);
166 		context->length = (unsigned char)r;
167 	}
168 }
169 
PHP_SNEFRUFinal(unsigned char digest[32],PHP_SNEFRU_CTX * context)170 PHP_HASH_API void PHP_SNEFRUFinal(unsigned char digest[32], PHP_SNEFRU_CTX *context)
171 {
172 	uint32_t i, j;
173 
174 	if (context->length) {
175 		SnefruTransform(context, context->buffer);
176 	}
177 
178 	context->state[14] = context->count[0];
179 	context->state[15] = context->count[1];
180 	Snefru(context->state);
181 
182 	for (i = 0, j = 0; j < 32; i++, j += 4) {
183 		digest[j] = (unsigned char) ((context->state[i] >> 24) & 0xff);
184 		digest[j + 1] = (unsigned char) ((context->state[i] >> 16) & 0xff);
185 		digest[j + 2] = (unsigned char) ((context->state[i] >> 8) & 0xff);
186 		digest[j + 3] = (unsigned char) (context->state[i] & 0xff);
187 	}
188 
189 	ZEND_SECURE_ZERO(context, sizeof(*context));
190 }
191 
php_snefru_unserialize(php_hashcontext_object * hash,zend_long magic,const zval * zv)192 static int php_snefru_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
193 {
194 	PHP_SNEFRU_CTX *ctx = (PHP_SNEFRU_CTX *) hash->context;
195 	int r = FAILURE;
196 	if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
197 		&& (r = php_hash_unserialize_spec(hash, zv, PHP_SNEFRU_SPEC)) == SUCCESS
198 		&& ctx->length < sizeof(ctx->buffer)) {
199 		return SUCCESS;
200 	} else {
201 		return r != SUCCESS ? r : -2000;
202 	}
203 }
204 
205 const php_hash_ops php_hash_snefru_ops = {
206 	"snefru",
207 	(php_hash_init_func_t) PHP_SNEFRUInit,
208 	(php_hash_update_func_t) PHP_SNEFRUUpdate,
209 	(php_hash_final_func_t) PHP_SNEFRUFinal,
210 	php_hash_copy,
211 	php_hash_serialize,
212 	php_snefru_unserialize,
213 	PHP_SNEFRU_SPEC,
214 	32,
215 	32,
216 	sizeof(PHP_SNEFRU_CTX),
217 	1
218 };
219