java - Cannot send AES encrypted messages of over 47 characters -
ello mates! creating aes encrypted chat program have ran issue; whenever message on 47 characters, displays "javax.crypto.illegalblocksizeexception: input length must multiple of 16 when decrypting padded cipher". understand error message can't seem figure out how fix it. here full code: chatclient.java package chat.application;
import java.awt.event.actionevent; import java.awt.event.actionlistener; import java.io.bufferedreader; import java.io.ioexception; import java.io.inputstreamreader; import java.io.printwriter; import java.net.socket; import javax.swing.jframe; import javax.swing.joptionpane; import javax.swing.jscrollpane; import javax.swing.jtextarea; import javax.swing.jtextfield; import javax.swing.text.*; import java.security.*; import java.util.logging.level; import java.util.logging.logger; import javax.crypto.*; import javax.crypto.spec.secretkeyspec; import sun.misc.*; import java.net.inetaddress; /* * known bugs: * message size limited 47 characters */ public class chatclient { bufferedreader in; printwriter out; jframe frame = new jframe("electron chatroom"); jtextfield textfield = new jtextfield(32); jtextarea messagearea = new jtextarea(8, 40); byte[] keyvalue = new byte[]{'5', '7', '3', '4', '5', '6', '3', '4', '9', '8', '5', '6', 'l', '9', '3', '4'}; final string algo = "aes"; string name; string myname; inetaddress ip = null; string errortype; /* * constructs client laying out gui , registering listener * textfield pressing return in listener sends * textfield contents server. note textfield * not editable, , becomes editable after client * receives nameaccepted message server. */ public class jtextfieldlimit extends plaindocument { private int limit; // optional uppercase conversion private boolean touppercase = false; jtextfieldlimit(int limit) { super(); this.limit = limit; } jtextfieldlimit(int limit, boolean upper) { super(); this.limit = limit; touppercase = upper; } public void insertstring (int offset, string str, attributeset attr) throws badlocationexception { if (str == null) return; if ((getlength() + str.length()) <= limit) { if (touppercase) str = str.touppercase(); super.insertstring(offset, str, attr); } } } public chatclient() { // layout gui textfield.seteditable(false); messagearea.seteditable(false); messagearea.setwrapstyleword(true); messagearea.setlinewrap(true); frame.getcontentpane().add(textfield, "north"); frame.getcontentpane().add(new jscrollpane(messagearea), "center"); frame.pack(); // add listeners textfield.addactionlistener(new actionlistener() { /** * responds pressing enter key in textfield sending * contents of text field server. clear text * area in preparation next message. */ @override public void actionperformed(actionevent e) { try { if ((textfield.gettext()).startswith("/")) { if ("electron".equals(myname)) { string command = (textfield.gettext()); out.println(command); textfield.settext(""); } } else { //encryption string encrypt = textfield.gettext(); key key = generatekey(); cipher c = cipher.getinstance(algo); c.init(cipher.encrypt_mode, key); byte[] encval = c.dofinal(encrypt.getbytes()); string input = new base64encoder().encode(encval); out.println(input); textfield.settext(""); } } catch (exception ex) { logger.getlogger(chatclient.class.getname()).log(level.severe, null, ex); } } }); } /** * prompt , return address of server. */ private string getserveraddress() { return joptionpane.showinputdialog( frame, "enter ip address of server:", "electron chatroom", joptionpane.question_message); } /** * prompt , return desired screen name. */ private string getname() { return joptionpane.showinputdialog( frame, "choose screen name:", "screen name selection", joptionpane.plain_message); } /** * connects server enters processing loop. */ private void run() throws ioexception { // make connection , initialize streams string serveraddress = getserveraddress(); socket socket = new socket(serveraddress, 9001); in = new bufferedreader(new inputstreamreader( socket.getinputstream())); out = new printwriter(socket.getoutputstream(), true); // process messages server, according protocol. while (true) { string line = in.readline(); if (line.startswith("submitname")) { if (line.length() == 18) { line = line.substring(11); system.out.println(line); switch (line) { case "error 1": errortype = "[error: name cannot blank]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); break; case "error 2": errortype = "[error: names 'admin'? seems legit...]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); break; case "error 3": errortype = "[error: have been banned]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); break; } } else if (line.length() == 10) { out.println(getname()); } } else if (line.startswith("nameaccepted")) { myname = line.substring(13); if (myname == "admin") { errortype = "[error: names 'admin'? seems legit...]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); } else if (myname == "admin") { errortype = "[error: names 'admin'? seems legit...]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); } else if (myname == "admin") { errortype = "[error: names 'admin'? seems legit...]"; joptionpane.showmessagedialog(frame, errortype); system.exit(0); } joptionpane.showmessagedialog(frame, "welcome " + myname + " (" + ip + ")"); ip = inetaddress.getlocalhost(); textfield.seteditable(true); //limits message length 47 characters (disabled debugging purposes) //textfield.setdocument(new jtextfieldlimit(47)); out.println(ip); } else if (line.startswith("servermessage")) { line = line.substring(14); messagearea.append(line + "\n"); messagearea.setcaretposition(messagearea.getdocument().getlength()); } else if (line.startswith("servercommand")) { line = line.substring(14); if (line.startswith("kick " + ip)) { system.exit(0); } } else if (line.startswith("fingerprint")) { ip = inetaddress.getlocalhost(); out.println(ip); } else if (line.startswith("name")) { name = line.substring(5); } else if (line.startswith("message")) { try { //decryption system.out.println(line); line = line.substring(8); string encrypteddata = line; system.out.println(line.length()); key key = generatekey(); cipher c = cipher.getinstance(algo); c.init(cipher.decrypt_mode, key); byte[] decordedvalue = new base64decoder().decodebuffer(encrypteddata); byte[] decvalue = c.dofinal(decordedvalue); string decryptedvalue = new string(decvalue); messagearea.append(name + ": " + decryptedvalue + "\n"); messagearea.setcaretposition(messagearea.getdocument().getlength()); } catch (exception ex) { logger.getlogger(chatclient.class.getname()).log(level.severe, null, ex); } } } } private key generatekey() throws exception { key key = new secretkeyspec(keyvalue, algo); return key; } /** * runs client application closeable frame. */ public static void main(string[] args) throws exception { chatclient client = new chatclient(); client.frame.setdefaultcloseoperation(jframe.exit_on_close); client.frame.setvisible(true); client.run(); } }
chatserver.java
package chat.application; import java.io.bufferedreader; import java.io.ioexception; import java.io.inputstreamreader; import java.io.printwriter; import java.net.serversocket; import java.net.socket; import java.util.hashset; /** * multi-threaded chat room server. when client connects server requests * screen name sending client text "submitname", , keeps * requesting name until unique 1 received. after client submits * unique name, server acknowledges "nameaccepted". messages * client broadcast other clients have submitted * unique screen name. broadcast messages prefixed "message ". * * because teaching example illustrate simple chat server, * there few features have been left out. 2 useful , * belong in production code: * * 1. protocol should enhanced client can send clean * disconnect messages server. * * 2. server should logging. */ public class chatserver { /** * port server listens on. */ private static final int port = 9001; /** * set of names of clients in chat room. maintained * can check new clients not registering name in use. */ private static hashset<string> names = new hashset<>(); /** * set of print writers clients. set kept * can broadcast messages. */ private static hashset<printwriter> writers = new hashset<>(); /** * set of print writers clients. set kept * can broadcast messages. */ private static hashset<string> bans = new hashset<>(); private static string[] names = new string[50]; private static string[] fingerprints = new string[50]; static int array = 0; static int index; /** * application main method, listens on port , spawns * handler threads. */ public static void main(string[] args) throws exception { system.out.println("chat server activated"); serversocket listener = new serversocket(port); try { while (true) { new handler(listener.accept()).start(); } } { listener.close(); } } /** * handler thread class. handlers spawned listening loop , * responsible dealing single client , broadcasting * messages. */ private static class handler extends thread { private string name; private string ban; private socket socket; private bufferedreader in; private printwriter out; private integer length; private string fingerprint; /** * constructs handler thread, squirreling away socket. * interesting work done in run method. */ public handler(socket socket) { this.socket = socket; } /** * services thread's client repeatedly requesting screen name * until unique 1 has been submitted, acknowledges name , * registers output stream client in global set, * repeatedly gets inputs , broadcasts them. */ @override public void run() { try { // create character streams socket. in = new bufferedreader(new inputstreamreader( socket.getinputstream())); out = new printwriter(socket.getoutputstream(), true); // request name client. keep requesting until // name submitted not used. note // checking existence of name , adding name // must done while locking set of names. while (true) { out.println("submitname"); name = in.readline(); length = name.length(); if (length == 0) { out.println("submitname error 1"); return; } if (name == "null") { out.println("submitname error 1"); return; } if (name == "admin") { out.println("submitname error 2"); return; } if (name == "admin") { out.println("submitname error 2"); return; } if (name == "admin") { out.println("submitname error 2"); return; } synchronized (bans) { out.println("fingerprint"); fingerprint = in.readline(); if (bans.contains(fingerprint)) { out.println("submitname error 3"); return; } } synchronized (names) { if (!names.contains(name)) { names.add(name); break; } } } // successful name has been chosen, add // socket's print writer set of writers // client can receive broadcast messages. out.println("nameaccepted " + name); names[array] = name; system.out.println(names[array]); fingerprints[array] = in.readline(); system.out.println(fingerprints[array]); array = array + 1; //announces user online (printwriter writer : writers) { writer.println("servermessage " + name + " online"); } system.out.println(names); writers.add(out); // accept messages client , broadcast them. // ignore other clients cannot broadcasted to. while (true) { string input = in.readline(); system.out.println(input); if (input == null) { return; } (printwriter writer : writers) { if (input.startswith("/")) { if ("electron".equals(name)) { //tracks hostname , ip address of user if (input.startswith("/track")) { input = input.substring(7); index = java.util.arrays.aslist(names).indexof(input); out.println("servermessage " + input + ": " + fingerprints[index]); //bans user returning until server deactivated } else if (input.startswith("/ban")) { input = input.substring(5); index = java.util.arrays.aslist(names).indexof(input); synchronized (bans) { bans.add(fingerprints[index]); } out.println("servermessage " + input + "(" + fingerprints[index] + ")" + " banned"); } else if (input.startswith("/kick")) { input = input.substring(6); index = java.util.arrays.aslist(names).indexof(input); out.println("servercommand kick " + fingerprints[index]); } else if (input.startswith("/deactivate")) { writer.println("servermessage server offline"); system.exit(0); } } } else { writer.println("name " + name); writer.println("message " + input); } } } } catch (ioexception e) { system.out.println(e); } { // client going down! remove name , print // writer sets, , close socket. (printwriter writer : writers) { writer.println("servermessage " + name + " offline"); } if (name != null) { names.remove(name); } if (out != null) { writers.remove(out); } try { socket.close(); } catch (ioexception e) { } } } } }
i have tried varying amount of text send, adding more padding, trying every input 1 - 1000 in order see if there pattern (there wasn't....). have researched on internet no avail.
thanks helping noob programmer 2nd program (really.)! have great week!
this true. aes block cypher, means encrypts 16 , 16 bytes @ time.
this means have pad message multiple of 16, , call multiple times , once each block. encryption, need add iv, , apply blocks. can difficult implement yourself, should let libraries it. javax.crypto library can that.
the solution select algorithm, found in the javadocs (or consult full list here).
try algo: aes/cbc/pkcs5padding