Advertisement
Guest User

Untitled

a guest
Dec 13th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.     Comamnd prompt IRC client with end-to-end encryption built in. Now with lots of comments on it!
  3. */
  4.  
  5. var net = require('net');
  6. var Base64 = require('js-base64').Base64;
  7.  
  8. var chan = ['#Tanan']; //Keep track of all channels the user has been connected.
  9.  
  10. /*
  11.         Declare variables necessary for the key exchange.
  12. */
  13.  
  14. var prime = 23;
  15. var generator = 5;
  16.  
  17. var privateKey = generateKey(prime);
  18. var receivedKey;
  19. var key;
  20. var starter;
  21.  
  22. console.log(privateKey);
  23.  
  24. var nick;
  25. var client = new net.Socket();
  26.  
  27. /*
  28.             Socket/core functions.
  29. */
  30.  
  31. function send(data) {
  32.     client.write(data + '\r\n'); //IRC messages need to have "\r\n" at the end of them when sent.
  33.     console.log(data);
  34. }
  35.  
  36. client.on('data', function(data) {
  37.     word = (data.toString('ascii')).split(" ");
  38.  
  39.     /*
  40.             Message handling.
  41.     */
  42.  
  43.     if (key == null) {
  44.         console.log(data.toString('ascii'));
  45.     } else {
  46.  
  47.         /*
  48.             Whenever you send a encrypted message,
  49.             the program automatically sends a hint that the message is encrypted.
  50.             So we have to check wether or not it's a message sent by other user,
  51.             and if it has the encryption hint.
  52.         */
  53.  
  54.         //Check if the message has been sent by other user and if it has the encryption hint.
  55.         if (word[1] == "PRIVMSG" && word[4] == "en") {
  56.  
  57.             //Make sure it only decrypts where it's necesary.
  58.             var tempWord = (data.toString('ascii')).split(" ");
  59.             tempWord.splice(0, 5);
  60.             tempWord = tempWord.join(" ");         
  61.  
  62.             var result = b64(tempWord, key, false); //Decrypt the message.
  63.  
  64.             /*
  65.                 Now that the message is decrypted, we want the user to know who sent the message.
  66.                 So what we do is that we take the message
  67.                 Eleminate everything surrounding the encryption of it
  68.                 And output it with the now, decrypted message.
  69.  
  70.                 That way the message will look just like a normal irc message, but only you can read it.
  71.             */
  72.            
  73.             tempWord = (data.toString('ascii')).split(" "); //"we take the message"
  74.            
  75.             //"Eleminate everything surrounding the encryption of it"
  76.             tempWord.splice(tempWord.length-2, 2);
  77.             tempWord = tempWord.join(" ");
  78.  
  79.             console.log(tempWord + result); //And output it with the now, decrypted message.
  80.         } else {
  81.  
  82.             //If it isn't, just print what has been sent.
  83.             console.log(data.toString('ascii'));
  84.         }
  85.     }
  86.  
  87.     for (var i = 0; i < word.length; i++) {
  88.  
  89.         //Handle pings.
  90.         if (word[i].match(/PING/)) {
  91.             send('PONG ' + word[i+1]);
  92.         }
  93.  
  94.         //Check if the user has connected to the IRC server correctly already.
  95.         if (word[i].match(/iwx/)) {
  96.  
  97.             console.log("Type /j #<channel> to join a channel and #<channel> <message> to send a message.");
  98.             console.log("Type /s #<channel> to start a end-to-end connection, \nand type /en #<channel> <message> to send a encrypted message.");
  99.             console.log("Type /q <nickname> to send a private message to that person. \n");
  100.  
  101.             //Check if it's just a person trying to glitch the client.
  102.             if (word[1] != 'PRIVMSG') {
  103.  
  104.                 //If it isn't, connect to all default channels.
  105.                 for (k in chan) {
  106.                     send('JOIN ' + chan[k]);
  107.                 }
  108.             }
  109.         }
  110.  
  111.         if (word[i].match(/generateKey/)) {
  112.            
  113.             //If anything goes wrong on the key exchange, do it all over again.
  114.             starter = true;
  115.             console.log("----------------------------------------------Connection failed, retrying..---------------------------------------------");
  116.             privateKey = generateKey(prime);
  117.  
  118.             send('PRIVMSG ' + word[2] + ' :publicKey ' +  ((Math.pow(generator, privateKey)) % prime));
  119.         }
  120.  
  121.         if (word[i] == ":publicKey") {
  122.             if (!starter) {
  123.  
  124.                 //Generating a new key whenever possible is very good for security.
  125.                 privateKey = generateKey(prime);
  126.             }
  127.  
  128.             receivedKey = parseInt(word[i+1]); //Store the received key.
  129.             key = (Math.pow(receivedKey, privateKey)) % prime; //Store the shared key. (k = rK^pK mod p)
  130.  
  131.             console.log('Type "/en #<channel> <message>" to send a encrypted message.');
  132.            
  133.             if (!starter) {
  134.  
  135.                 //Handle the connection request.
  136.                 send('PRIVMSG ' + word[2] + ' :publicKey ' +  ((Math.pow(generator, privateKey)) % prime));
  137.             } else {
  138.                 if (key > 7 || key == 0) {
  139.                     /*
  140.                         If we get a key that is way too big, we will send unreversable encryption.
  141.                         Which is definetly not what we want.
  142.                     */
  143.                    
  144.                     console.log("----------------------------------------------Connection failed, retrying..---------------------------------------------");
  145.                     startConnection(word[2]); //Restart the key exchange.
  146.                     return;
  147.                 }
  148.             }
  149.  
  150.             starter = false;
  151.         }
  152.     }
  153. });
  154.  
  155. client.on('close', function() {
  156.     console.log('------Connection closed------');
  157. });
  158.  
  159. /*
  160.             User interface functions.
  161. */
  162.  
  163. var stdin = process.openStdin();
  164.  
  165. stdin.addListener("data", function(d) {
  166.     if (nick) {
  167.         var word = (d.toString().trim()).split(" ");
  168.  
  169.         /*
  170.                 Debugging commands.
  171.         */
  172.  
  173.         if (word[0] == "varList") {
  174.             console.log(privateKey + " " + receivedKey + " " + key + " " + ((Math.pow(generator, privateKey)) % prime));
  175.             return;
  176.         }
  177.  
  178.         if (word[0] == "key") {
  179.             console.log(key);
  180.             return;
  181.         }
  182.  
  183.         if (word[0] == "privateKey") {
  184.             console.log(privateKey);
  185.             return;
  186.         }
  187.  
  188.         if (word[0] == "receivedKey") {
  189.             console.log(receivedKey);
  190.             return;
  191.         }
  192.  
  193.         if(word[0] == "publicKey") {
  194.             console.log(((Math.pow(generator, privateKey)) % prime));
  195.             return;
  196.         }
  197.  
  198.         /*
  199.                 Socket commands.
  200.         */
  201.  
  202.         if (word[0] == "generateKey") {
  203.             privateKey = generateKey(prime);
  204.             console.log(privateKey);
  205.             return;
  206.         }
  207.  
  208.         if (word[0] == "startConnection" || word[0] == "secureConnection" || word[0] == "/secure" || word[0] == "/s" || word[0] == "secure") {
  209.             startConnection(word[1]);  
  210.             return;
  211.         }
  212.  
  213.         /*
  214.                 Basic IRC commands.
  215.         */
  216.  
  217.         if (word[0] == "/j" || word[0] == "/join" || word[0] == "join" || word[0] == "JOIN") {
  218.             send('JOIN ' + word[1]);
  219.             chan[chan.length+1] = word[1]; //Keep track of the channels the user is connected to.
  220.             return;
  221.         }
  222.  
  223.  
  224.         if (word[0] == "/k" || word[0] == "/kick" || word[0] == "kick") {
  225.             /*
  226.                 Handling kick commands need to have extra care,
  227.                 since you want it to have multiple words as a reason for the kick.
  228.                
  229.                 What we do is that we take both,
  230.                 the nickname of the person the user wants to kick and the channel that the person is in
  231.                 and then we store it on a temporary array (tempArr).
  232.                 After we have done that, we eleminate the nickname and the channel from the original array,
  233.                 so we can finally make a string out of the kick reason and send it to the server.
  234.             */
  235.  
  236.             var tempArr = [word[1], word[2]]; //Store the nickname and channel on a temporary array.
  237.  
  238.             //Check wether or not the user has typed in a reason or not.
  239.             if (word[3]) {
  240.                 word.splice(0, 3); //Eleminate both, the nickname and the channel from the original array
  241.  
  242.                 //Perform the kick with the reason the user has gave us.
  243.                 send("KICK " + tempArr[0] + " " + tempArr[1] + " " + word.join(" "));
  244.             } else {
  245.  
  246.                 /*
  247.                     If the user hasn't tiped in the reason why he is kicking the other person,
  248.                     kick him without giving reasoning.
  249.                 */
  250.  
  251.                 send("KICK " + tempArr[0] + " " + tempArr[1]);         
  252.             }
  253.  
  254.             return;
  255.         }
  256.  
  257.         /*
  258.                 Basic IRC channel mode commands.
  259.         */
  260.  
  261.         if (word[0] == '/o' || word[0] == '/O' || word[0] == '/op' || word[0] == '/OP' || word[0] == 'op' || word[0] == 'OP') {
  262.             send('MODE ' + word[1] + ' +o ' + word[2]);
  263.             return;
  264.         }
  265.  
  266.         if (word[0] == '/v' || word[0] == '/V' || word[0] == '/voice' || word[0] == '/VOICE' || word[0] == 'voice' || word[0] == 'VOICE') {
  267.             send('MODE ' + word[1] + ' +v ' + word[2]);
  268.             return;
  269.         }
  270.  
  271.         if (word[0] == '/h' || word[0] == '/H' || word[0] == '/hop' || word[0] == '/HOP' || word[0] == 'hop' || word[0] == 'HOP') {
  272.             send('MODE ' + word[1] + ' +h ' + word[2]);
  273.             return;
  274.         }
  275.  
  276.         /*
  277.                 Actual user output.
  278.         */
  279.  
  280.         if (word[0] == '/q' || word[0] == '/Q' || word[0] == '/query' || word[0] == '/QUERY' || word[0] == 'query' || word[0] == 'QUERY') {
  281.            
  282.             //Let's not send "/q <nick>", nobody does that.
  283.             var tempWord = (d.toString().trim()).split(" ");
  284.             tempWord.splice(0, 2);
  285.             tempWord = tempWord.join(" ");         
  286.  
  287.             send('PRIVMSG ' + word[1] + ' :' + tempWord);
  288.             return;
  289.         }      
  290.  
  291.         //Check wether or not the user has made a key exchange and if he wants his message to me encrypted.
  292.         if (key && word[0] == '/en') {
  293.  
  294.             //We don't want to send /en <channel>, that would look kind of weird.
  295.             var tempWord = (d.toString().trim()).split(" ");
  296.             tempWord.splice(0, 2);
  297.             tempWord = tempWord.join(" ");
  298.  
  299.             //Send the encrypted message with a hint that the message is encrypted so the other user can decrypt it.
  300.             send('PRIVMSG ' + word[1] + ' : en ' + b64(tempWord, key, true));
  301.         } else {
  302.             if (!starter) {
  303.  
  304.                 //Check if the user is sending a message to a channel.
  305.                 for (i in chan) {
  306.                     if (word[0] == chan[i]) {
  307.  
  308.                         //Sending #<channel> after every message would look weird, so let's not do it.
  309.                         var tempWord = (d.toString().trim()).split(" ");
  310.                         tempWord.splice(0, 1);
  311.                         tempWord = tempWord.join(" ");
  312.  
  313.                         send('PRIVMSG ' + word[0] + ' :' + d.toString().trim()); //Send the message.
  314.                         return;
  315.                     }
  316.                 }
  317.  
  318.  
  319.                 send(d.toString().trim()); //If the user didn't type in a channel, just send the message anyway.
  320.             }
  321.         }
  322.     } else {
  323.  
  324.         nick = d.toString().trim(); //Set the nickname.
  325.  
  326.         //Connect to the IRC server.
  327.         client.connect(6667, 'irc.toribash.com', function() {
  328.             send('NICK ' + nick);
  329.             send('USER ' + nick + ' 8 * : ' + nick);
  330.         });
  331.     }
  332. });
  333.  
  334. /*
  335.             Cryptography functions.
  336. */
  337.  
  338. function cipher(input, key, op, bool, boolX, boolY, bool2) {
  339.    
  340.     /*
  341.         This function does something similar to a ceaser cipher.
  342.         In fact, the only difference is that it can eleminate some few words
  343.         and it's not limited to just shifting by 3, it can shift as much as you desire.
  344.     */
  345.  
  346.     //Create a temporary array in case it's necessary to eleminate some few words.
  347.     var tempWord = input.split(" ");
  348.    
  349.     if (bool == true) {
  350.         tempWord.splice(boolX, boolY);
  351.     }
  352.  
  353.     tempWord = tempWord.join(" "); //Transform the array into a string.
  354.  
  355.     var charString = tempWord.split(""); //Transfor the string we have just created into a array of characters.
  356.     var charCypher = []; //Create array that will store the cypher.
  357.  
  358.     //Check if the user wants to encrypt or decrypt the array.
  359.     if (op == '-') {
  360.  
  361.         //Decrypt the array.
  362.         for (i in charString) {
  363.             charCypher[i] = String.fromCharCode((charString[i].charCodeAt())-key);
  364.         }
  365.     } else {
  366.  
  367.         //Encrypt the array.
  368.         for (i in charString) {
  369.             charCypher[i] = String.fromCharCode((charString[i].charCodeAt())+key);
  370.         }
  371.     }
  372.  
  373.     var result = charCypher.join(""); //Turn array into a now, decrypted or encrypted string.
  374.  
  375.     return result; //I think this is pretty obvious, isn't it?
  376. }
  377.  
  378. function b64(input, key, bool) {
  379.  
  380.     /*
  381.         This is the encryption algorithm that is actually used in the end-to-end encryption.
  382.     */
  383.  
  384.     var a;
  385.  
  386.     //Check if the function has to encrypt or decrypt the message.
  387.     if (bool == true) {
  388.         a = cipher(input, key, '+', false, null, null, false); //Encrypt the input with the cipher.
  389.  
  390.         a = Base64.encode(a); //Encrypt with base64 the input. Pretty obvious, but anyway.
  391.         a = cipher(a, key, '+', false, null, null, false); //Encrypt the input again with the cipher.
  392.     } else {
  393.         a = cipher(input, key, '-', false, null, null, false); //Decipher the base64 encryption.
  394.  
  395.         a = Base64.decode(a); //Decrypt the base64 encryption.
  396.         a = cipher(a, key, '-', false, null, null, false); //Decipher the actual message.
  397.     }
  398.  
  399.     return a;
  400. }
  401.  
  402. /*
  403.             Key exchange functions.
  404. */
  405.  
  406. //This function generates a number that can be used for the key exchange.
  407. function generateKey(prime) {
  408.     var a;
  409.  
  410.     while(true) {
  411.         a = Math.floor(((Math.random() * (prime*20)) + 1)/prime);
  412.  
  413.         if (a > 1) {
  414.             break;
  415.         }
  416.     }
  417.  
  418.     return a;
  419. }
  420.  
  421. //This function is used to start the key exchange. (Public key = g^pK mod p)
  422. function startConnection(channel) {
  423.  
  424.     //Generating a new private key when possible is always good for security.
  425.     privateKey = generateKey(prime);
  426.     send('PRIVMSG ' + channel + ' :publicKey ' +  ((Math.pow(generator, privateKey)) % prime));
  427.     starter = true;
  428. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement