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