Subversion Repositories cryptochat

Rev

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>