summaryrefslogtreecommitdiff
path: root/crypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypt.c')
-rw-r--r--crypt.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/crypt.c b/crypt.c
new file mode 100644
index 0000000..6daaa03
--- /dev/null
+++ b/crypt.c
@@ -0,0 +1,289 @@
1/*
2 +----------------------------------------------------------------------+
3 | Suhosin Version 1 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2007 The Hardened-PHP Project |
6 | Copyright (c) 2007-2016 SektionEins GmbH |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Stefan Esser <sesser@sektioneins.de> |
17 | Ben Fuhrmannek <ben.fuhrmannek@sektioneins.de> |
18 +----------------------------------------------------------------------+
19*/
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include "php.h"
26#include "php_suhosin7.h"
27#include "ext/standard/base64.h"
28// #include "sha256.h"
29#include "ext/hash/php_hash.h"
30#include "ext/hash/php_hash_sha.h"
31
32// TODO: IPv6 handling
33
34static void suhosin_get_ipv4(char *buf)
35{
36 char *raddr = suhosin_getenv(ZEND_STRL("REMOTE_ADDR"));
37 int i;
38
39
40 if (raddr == NULL) {
41 memset(buf, 0, 4);
42 return;
43 }
44
45 for (i=0; i<4; i++) {
46 if (raddr[0] == 0) {
47 buf[i] = 0;
48 } else {
49 buf[i] = strtol(raddr, &raddr, 10);
50 if (raddr[0] == '.') {
51 raddr++;
52 }
53 }
54 }
55}
56
57zend_string *suhosin_encrypt_string(char *str, int len, char *var, int vlen, char *key)
58{
59 int padded_len, i, slen;
60 unsigned char *crypted, *tmp;
61 unsigned int check = 0x13579BDF;
62
63 if (str == NULL) {
64 return NULL;
65 }
66
67 if (len == 0) {
68 return ZSTR_EMPTY_ALLOC();
69 }
70
71 suhosin_aes_gkey(4, 8, key);
72
73 padded_len = ((len+15) & ~0xF);
74 crypted = emalloc(16+padded_len+1);
75 memset(crypted, 0xff, 16+padded_len+1);
76 memcpy(crypted+16, str, len+1);
77
78 /* calculate check value */
79 for (i = 0; i < vlen; i++) {
80 check = (check << 3) | (check >> (32-3));
81 check += check << 1;
82 check ^= (unsigned char)var[i];
83 }
84 for (i = 0; i < len; i++) {
85 check = (check << 3) | (check >> (32-3));
86 check += check << 1;
87 check ^= (unsigned char)str[i];
88 }
89
90 /* store ip value */
91 suhosin_get_ipv4((char *)crypted + 4);
92
93 /* store check value */
94 crypted[8] = check & 0xff;
95 crypted[9] = (check >> 8) & 0xff;
96 crypted[10] = (check >> 16) & 0xff;
97 crypted[11] = (check >> 24) & 0xff;
98
99 /* store original length */
100 crypted[12] = len & 0xff;
101 crypted[13] = (len >> 8) & 0xff;
102 crypted[14] = (len >> 16) & 0xff;
103 crypted[15] = (len >> 24) & 0xff;
104
105 for (i = 0, tmp = crypted; i < padded_len + 16; i += 16, tmp += 16) {
106 if (i > 0) {
107 int j;
108 for (j=0; j<16; j++) tmp[j] ^= tmp[j-16];
109 }
110 suhosin_aes_encrypt((char *)tmp);
111 }
112
113 zend_string *zs = php_base64_encode(crypted, padded_len+16);
114 efree(crypted);
115 // slen=strlen((char *)tmp);
116 for (i = 0; i < ZSTR_LEN(zs); i++) {
117 switch (ZSTR_VAL(zs)[i]) {
118 case '/': ZSTR_VAL(zs)[i]='-'; break;
119 case '=': ZSTR_VAL(zs)[i]='.'; break;
120 case '+': ZSTR_VAL(zs)[i]='_'; break;
121 }
122 }
123 return zs;
124// return NULL;
125}
126
127zend_string *suhosin_decrypt_string(char *str, int padded_len, char *var, int vlen, char *key, int check_ra)
128{
129 SDEBUG("decrypting string |%s|", str);
130 int i;
131 unsigned int check = 0x13579BDF;
132
133 if (str == NULL) {
134 return NULL;
135 }
136
137 if (padded_len == 0) {
138 return ZSTR_EMPTY_ALLOC();
139 }
140 suhosin_aes_gkey(4, 8, key);
141
142 for (i = 0; i < padded_len; i++) {
143 switch (str[i]) {
144 case '-': str[i]='/'; break;
145 case '.': str[i]='='; break;
146 case '_': str[i]='+'; break;
147 }
148 }
149
150 zend_string *decrypted_zs = php_base64_decode((unsigned char *)str, padded_len);
151 if (decrypted_zs == NULL) {
152 return NULL;
153 }
154
155 unsigned char *decrypted = (unsigned char*)ZSTR_VAL(decrypted_zs);
156 int len = ZSTR_LEN(decrypted_zs);
157 SDEBUG("len=%d", len);
158 if (len < 2*16 || (len % 16) != 0) {
159 goto error_out;
160 }
161
162 unsigned char *tmp;
163 for (i = len - 16, tmp = decrypted + i; i >= 0; i -= 16, tmp -= 16) {
164 suhosin_aes_decrypt((char *)tmp);
165 if (i > 0) {
166 int j;
167 for (j=0; j<16; j++) tmp[j] ^= tmp[j-16];
168 }
169 }
170 SDEBUG("tmp=%s", tmp);
171 /* retrieve orig_len */
172 int o_len = decrypted[15];
173 o_len <<= 8;
174 o_len |= decrypted[14];
175 o_len <<= 8;
176 o_len |= decrypted[13];
177 o_len <<= 8;
178 o_len |= decrypted[12];
179
180 if (o_len < 0 || o_len > len-16) {
181 goto error_out;
182 }
183
184 /* calculate check value */
185 for (i = 0; i<vlen; i++) {
186 check = (check << 3) | (check >> (32-3));
187 check += check << 1;
188 check ^= (unsigned char)var[i];
189 }
190 for (i = 0; i<o_len; i++) {
191 check = (check << 3) | (check >> (32-3));
192 check += check << 1;
193 check ^= decrypted[16+i];
194 }
195
196 /* check value */
197 int invalid = (decrypted[8] != (check & 0xff)) ||
198 (decrypted[9] != ((check >> 8) & 0xff)) ||
199 (decrypted[10] != ((check >> 16) & 0xff)) ||
200 (decrypted[11] != ((check >> 24) & 0xff));
201
202 /* check IP */
203 if (check_ra) {
204 if (check_ra > 4) {
205 check_ra = 4;
206 }
207 char buf[4];
208 suhosin_get_ipv4(&buf[0]);
209 if (memcmp(buf, decrypted+4, check_ra) != 0) {
210 goto error_out;
211 }
212 }
213
214 if (invalid) {
215 goto error_out;
216 }
217
218 memmove(decrypted, decrypted+16, o_len);
219 decrypted[o_len] = 0;
220 ZSTR_LEN(decrypted_zs) = o_len;
221 /* we do not realloc() here because 16 byte less
222 is simply not worth the overhead */
223 return decrypted_zs;
224
225error_out:
226 SDEBUG("error_out");
227 if (decrypted_zs) {
228 zend_string_release(decrypted_zs);
229 }
230 return NULL;
231}
232
233char *suhosin_generate_key(char *key, zend_bool ua, zend_bool dr, long raddr, char *cryptkey)
234{
235 char *_ua = NULL;
236 char *_dr = NULL;
237 char *_ra = NULL;
238 PHP_SHA256_CTX ctx;
239
240 if (ua) {
241 _ua = suhosin_getenv(ZEND_STRL("HTTP_USER_AGENT"));
242 }
243
244 if (dr) {
245 _dr = suhosin_getenv(ZEND_STRL("DOCUMENT_ROOT"));
246 }
247
248 if (raddr > 0) {
249 _ra = suhosin_getenv(ZEND_STRL("REMOTE_ADDR"));
250 }
251
252 SDEBUG("KEY: %s - UA: %s - DR: %s - RA: %s", key,_ua,_dr,_ra);
253
254 PHP_SHA256Init(&ctx);
255 if (key == NULL || *key == 0) {
256 PHP_SHA256Update(&ctx, (unsigned char*)ZEND_STRL("D3F4UL7"));
257 } else {
258 PHP_SHA256Update(&ctx, (unsigned char*)key, strlen(key));
259 }
260 if (_ua) {
261 PHP_SHA256Update(&ctx, (unsigned char*)_ua, strlen(_ua));
262 }
263 if (_dr) {
264 PHP_SHA256Update(&ctx, (unsigned char*)_dr, strlen(_dr));
265 }
266 if (_ra) {
267 if (raddr >= 4) {
268 PHP_SHA256Update(&ctx, (unsigned char*)_ra, strlen(_ra));
269 } else {
270 long dots = 0;
271 char *tmp = _ra;
272
273 while (*tmp) {
274 if (*tmp == '.') {
275 dots++;
276 if (dots == raddr) {
277 break;
278 }
279 }
280 tmp++;
281 }
282 PHP_SHA256Update(&ctx, (unsigned char*)_ra, tmp-_ra);
283 }
284 }
285 PHP_SHA256Final((unsigned char *)cryptkey, &ctx);
286 cryptkey[32] = 0; /* uhmm... not really a string */
287
288 return cryptkey;
289}