Subversion Repositories cryptochat

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  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.  */
  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>
  296.