Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | <?php |
2 | |||
5 | daniel-mar | 3 | /* |
4 | * ViaThinkSoft CryptoChat |
||
5 | * Copyright 2014 - 2018 Daniel Marschall, ViaThinkSoft |
||
6 | * |
||
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
8 | * you may not use this file except in compliance with the License. |
||
9 | * You may obtain a copy of the License at |
||
10 | * |
||
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
12 | * |
||
13 | * Unless required by applicable law or agreed to in writing, software |
||
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
16 | * See the License for the specific language governing permissions and |
||
17 | * limitations under the License. |
||
18 | */ |
||
2 | daniel-mar | 19 | |
20 | // ----------------------------------------------------------------------------------------------- |
||
21 | |||
22 | require __DIR__ . '/../config/config.inc.php'; |
||
23 | define('PRODUCT_NAME', 'CryptoChat'); |
||
24 | define('MCC_VER', trim(file_get_contents(__DIR__ . '/../VERSION'))); |
||
25 | |||
26 | header('Content-type: text/html; charset=utf-8'); |
||
27 | |||
28 | ?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
||
29 | "http://www.w3.org/TR/html4/loose.dtd"> |
||
30 | |||
31 | <html> |
||
32 | |||
33 | <head> |
||
34 | <META HTTP-EQUIV="content-type" CONTENT="text/html; charset=utf-8"> |
||
35 | <title><?php echo PRODUCT_NAME; ?> - Manually encrypt chat lines</title> |
||
36 | |||
37 | <script type="text/javascript" src="../<?php echo DEP_DIR_CRYPTOJS; ?>/rollups/sha256.js"></script> |
||
38 | <script type="text/javascript" src="../<?php echo DEP_DIR_CRYPTOJS; ?>/rollups/sha1.js"></script> |
||
39 | <script type="text/javascript" src="../<?php echo DEP_DIR_CRYPTOJS; ?>/rollups/aes.js"></script> |
||
40 | <script type="text/javascript" src="../<?php echo DEP_DIR_CRYPTOJS; ?>/rollups/md5.js"></script> |
||
41 | |||
42 | <script type="text/javascript"> |
||
43 | |||
44 | var roomSalt = null; |
||
45 | |||
46 | // http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript/1349426#1349426 |
||
47 | function randomString(len) { |
||
48 | var text = ""; |
||
49 | var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
||
50 | |||
51 | for( var i=0; i < len; i++ ) { |
||
52 | text += possible.charAt(Math.floor(Math.random() * possible.length)); |
||
53 | } |
||
54 | |||
55 | return text; |
||
56 | } |
||
57 | |||
58 | // -------------------------------------------- |
||
59 | |||
60 | // --- MD5 |
||
61 | |||
62 | var selftest_md5_finished = false; |
||
63 | function selftest_md5() { |
||
64 | if (selftest_md5_finished) return; |
||
65 | selftest_md5_finished = true; |
||
66 | |||
67 | var errors = ""; |
||
68 | cmp_a = CryptoJS.enc.Base64.stringify(CryptoJS.MD5("Message")); |
||
69 | cmp_b = "TCqP5+ryRyHMep8BdRFb1A=="; |
||
70 | if (cmp_a !== cmp_b) { |
||
71 | errors += "MD5 self test failed!\n"; |
||
72 | console.error("MD5 self test failed: '" + cmp_a + "' vs. '" + cmp_b + "'"); |
||
73 | } |
||
74 | |||
75 | if (errors) { |
||
76 | alert(errors+"\nYour browser seems to be buggy. Decryption of particular messages might fail."); |
||
77 | } else { |
||
78 | console.info("AES self test passed"); |
||
79 | } |
||
80 | } |
||
81 | |||
82 | function md5(message) { |
||
83 | selftest_md5(); |
||
84 | var hash = CryptoJS.MD5(message); |
||
85 | hash = CryptoJS.enc.Base64.stringify(hash); |
||
86 | return hash; |
||
87 | } |
||
88 | |||
89 | // --- SHA1 |
||
90 | |||
91 | var selftest_sha1_finished = false; |
||
92 | function selftest_sha1() { |
||
93 | if (selftest_sha1_finished) return; |
||
94 | selftest_sha1_finished = true; |
||
95 | |||
96 | var errors = ""; |
||
97 | cmp_a = CryptoJS.enc.Base64.stringify(CryptoJS.SHA1("Message")); |
||
98 | cmp_b = "aPQUX+593navzrkQFlkkrRTPDQA="; |
||
99 | if (cmp_a !== cmp_b) { |
||
100 | errors += "SHA1 self test failed!\n"; |
||
101 | console.error("SHA1 self test failed: '" + cmp_a + "' vs. '" + cmp_b + "'"); |
||
102 | } |
||
103 | |||
104 | if (errors) { |
||
105 | alert(errors+"\nYour browser seems to be buggy. Decryption of particular messages might fail."); |
||
106 | } else { |
||
107 | console.info("SHA1 self test passed"); |
||
108 | } |
||
109 | } |
||
110 | |||
111 | function sha1(message) { |
||
112 | selftest_sha1(); |
||
113 | var hash = CryptoJS.SHA1(message); |
||
114 | hash = CryptoJS.enc.Base64.stringify(hash); |
||
115 | return hash; |
||
116 | } |
||
117 | |||
118 | function sha1_base16(message) { |
||
119 | selftest_sha1(); |
||
120 | return CryptoJS.SHA1(message).toString(); |
||
121 | } |
||
122 | |||
123 | // --- SHA256 |
||
124 | |||
125 | var selftest_sha256_finished = false; |
||
126 | function selftest_sha256() { |
||
127 | if (selftest_sha256_finished) return; |
||
128 | selftest_sha256_finished = true; |
||
129 | |||
130 | var errors = ""; |
||
131 | cmp_a = CryptoJS.enc.Base64.stringify(CryptoJS.SHA256("Message")); |
||
132 | cmp_b = "L3dmip37+NWEi57rSnFFypTG7ZI25Kdz9tyvpRMrL5E="; |
||
133 | if (cmp_a !== cmp_b) { |
||
134 | errors += "SHA256 self test failed!\n"; |
||
135 | console.error("SHA256 self test failed: '" + cmp_a + "' vs. '" + cmp_b + "'"); |
||
136 | } |
||
137 | |||
138 | if (errors) { |
||
139 | alert(errors+"\nYour browser seems to be buggy. Decryption of particular messages might fail."); |
||
140 | } else { |
||
141 | console.info("AES self test passed"); |
||
142 | } |
||
143 | } |
||
144 | |||
145 | function sha256(message) { |
||
146 | selftest_sha256(); |
||
147 | var hash = CryptoJS.SHA256(message); |
||
148 | hash = CryptoJS.enc.Base64.stringify(hash); |
||
149 | return hash; |
||
150 | } |
||
151 | |||
152 | // --- AES |
||
153 | |||
154 | var selftest_aes_finished = false; |
||
155 | function selftest_aes() { |
||
156 | if (selftest_aes_finished) return; |
||
157 | selftest_aes_finished = true; |
||
158 | |||
159 | var errors = ""; |
||
160 | var cmp_a = CryptoJS.AES.decrypt("U2FsdGVkX19kJJkA0NL7WJRdXKrdqDcf6A2yDODaL2g=", "Secret Passphrase").toString(CryptoJS.enc.Utf8); |
||
161 | var cmp_b = "Message"; |
||
162 | if ((cmp_a !== cmp_b) || (aes_dec(aes_enc("Message")) !== "Message")) { |
||
163 | errors += "AES self test failed!\n"; |
||
164 | console.error("AES self test failed: '" + cmp_a + "' vs. '" + cmp_b + "'"); |
||
165 | } |
||
166 | |||
167 | if (errors) { |
||
168 | alert(errors+"\nYour browser seems to be buggy. Decryption of particular messages might fail."); |
||
169 | } else { |
||
170 | console.info("AES self test passed"); |
||
171 | } |
||
172 | } |
||
173 | |||
174 | function aes_enc(msg, ver) { |
||
175 | // ver is currently not used |
||
176 | selftest_aes(); |
||
177 | var passwd = getPassword(); |
||
178 | return CryptoJS.AES.encrypt(msg, roomSalt+passwd); |
||
179 | } |
||
180 | |||
181 | function aes_dec(msg, ver) { |
||
182 | // ver is currently not used |
||
183 | selftest_aes(); |
||
184 | var passwd = getPassword(); |
||
185 | try { |
||
186 | return CryptoJS.AES.decrypt(msg, roomSalt+passwd).toString(CryptoJS.enc.Utf8); |
||
187 | } catch (e) { |
||
188 | return null; |
||
189 | } |
||
190 | } |
||
191 | |||
192 | # --- |
||
193 | |||
194 | // Alternative hash digest for compatibility issues |
||
195 | // Some browsers like Jumanji have problems using SHA1 or SHA2, but work with MD5, e.g. |
||
196 | // Jumanji 1.1.2.4 (versionsangabe nicht sicher) ist inkompatibel mit CryptoJS 3.1.2 |
||
197 | // UA = "Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/534.26+ (KHTML, like Gecko) Version/5.0 Safari/534.26+ jumanji/0.0" |
||
198 | // CryptoJS.MD5("Message"): |
||
199 | // - Normal: 4c2a8fe7eaf24721cc7a9f0175115bd4 |
||
200 | // - Jumanji: 4c2a8fe7eaf24721cc7a9f0175115bd4 (OK) |
||
201 | // CryptoJS.SHA1("Message"): |
||
202 | // - Normal: 68f4145fee7dde76afceb910165924ad14cf0d00 |
||
203 | // - Jumanji: 5a5aa74ecae1d696900b034d5f1b71497c170ea0 (Error) |
||
204 | // CryptoJS.SHA256("Message"): |
||
205 | // - Normal: 2f77668a9dfbf8d5848b9eeb4a7145ca94c6ed9236e4a773f6dcafa5132b2f91 |
||
206 | // - Jumanji: 5a28f8b8778c15a166f7f17ebb89ce8e8381fbb5e39ddc2511239793119a649e (Error) |
||
207 | // CryptoJS.AES.encrypt("Message", "Secret Passphrase"): |
||
208 | // - Normal: U2FsdGVkX19zlzNcfljComkcU0A7XfZ+gzZbI+GyFm0= |
||
209 | // - Jumanji: U2FsdGVkX19kJJkA0NL7WJRdXKrdqDcf6A2yDODaL2g= (OK) |
||
210 | // This is a fast version (4x MD5) necessary for slow computers with ARM architecture |
||
211 | function specialMD5fast4(message) { |
||
212 | var a = md5("IuErOmVyPeL2ek6e16vkjTWjssgLmd" + message); |
||
213 | var b = md5("8wxdm3mVi8UQXdboJvCctYwm8ZxTyX" + message); |
||
214 | return md5(a+b) + md5(b+a); |
||
215 | } |
||
216 | |||
217 | function specialHash(val, entrySalt, version) { |
||
218 | var hash = null; |
||
219 | if (version == 1) { |
||
220 | hash = sha256(roomSalt+entrySalt+val); |
||
221 | } else if (version == 2) { |
||
222 | hash = specialMD5fast4(roomSalt+entrySalt+val); |
||
223 | } else { |
||
224 | console.error("Version " + version + " is unknown at specialHash()"); |
||
225 | return null; |
||
226 | } |
||
227 | return entrySalt + "_" + hash + "_ver" + version; |
||
228 | } |
||
229 | |||
230 | // -------------------------------------------- |
||
231 | |||
232 | function getPassword() { |
||
233 | return document.getElementById("key").value; |
||
234 | } |
||
235 | |||
236 | function cbLine(str, p1, p2, p3, offset, s) { |
||
237 | var ver = document.getElementById("ver").value; |
||
238 | var passwd = document.getElementById("key").value; |
||
239 | var entrySalt = randomString(20); |
||
240 | var hash = specialHash(passwd, entrySalt, ver); |
||
241 | |||
242 | return "(date: "+p1+")(user: "+p2+")(dec_"+hash+": "+aes_enc(p3,ver)+")<br>\n"; |
||
243 | } |
||
244 | |||
245 | function convert() { |
||
246 | var ses_room = document.getElementById("room").value; |
||
247 | var xsalt = document.getElementById("xsalt").value; |
||
248 | roomSalt = sha1_base16(xsalt + ses_room); |
||
249 | |||
250 | var message = document.getElementById("in").value + "\n"; |
||
251 | message = message.replace(/(.+?) - \[(.+?)\]: (.+?)\n/g, cbLine); |
||
252 | document.getElementById("out").value = message; |
||
253 | } |
||
254 | |||
255 | function initPage() { |
||
256 | document.getElementById("out").value = ""; |
||
257 | } |
||
258 | </script> |
||
259 | |||
260 | </head> |
||
261 | |||
262 | <body onload="initPage();"> |
||
263 | |||
264 | <h1>Manually encrypt chat lines</h1> |
||
265 | |||
266 | <table border="0" cellpadding="5" cellspacing="0"> |
||
267 | <tr> |
||
268 | <td>Server's X_SALT: </td> |
||
269 | <td><input style="width:500px" id="xsalt" value="<?php if (!KEEP_X_SALT_SECRET) echo X_SALT; ?>"></td> |
||
270 | </tr><tr> |
||
271 | <td>Algorithm: </td> |
||
272 | <td><select id="ver"> |
||
273 | <option value="1"<?php if (CFG_CIPHERSUITE == 1) echo ' selected'; ?>>[1] SHA256</option> |
||
274 | <option value="2"<?php if (CFG_CIPHERSUITE == 2) echo ' selected'; ?>>[2] specialMD5fast4</option> |
||
275 | </select></td> |
||
276 | </tr><tr> |
||
277 | <td>Key: </td> |
||
278 | <td><input style="width:500px" id="key"></td> |
||
279 | </tr><tr> |
||
280 | <td>Chatroom name: </td> |
||
281 | <td><input style="width:500px" id="room"></td> |
||
282 | </tr><tr> |
||
283 | <td colspan="2">Input:<br> |
||
284 | <textarea id="in" cols="100" rows="6">2014-12-31 14:21:20 - [Daniel]: Hello world! |
||
285 | 2014-12-31 14:21:22 - [Daniel]: Example!</textarea><br></td> |
||
286 | </tr><tr> |
||
287 | <td colspan="2"><input type="button" onclick="convert();" value="Convert"><br></td> |
||
288 | </tr><tr> |
||
289 | <td colspan="2">Output:<br> |
||
290 | <textarea id="out" cols="100" rows="6"></textarea></td> |
||
291 | </tr> |
||
292 | </table><br> |
||
293 | </body> |
||
294 | |||
295 | </html> |