|
|
Subject:
Java encryption problem
Category: Computers > Programming Asked by: gadman-ga List Price: $25.00 |
Posted:
10 May 2003 11:46 PDT
Expires: 09 Jun 2003 11:46 PDT Question ID: 202041 |
Hello, I'm having a problem with Java Encrption. I've written a class that encyrpts a string and then tries to decrypt that same string. My code works on one server (development machine Sun- UNIX). When I move it to a production machine (Sun - UNIX) it doesn't work. The failure is that the code tries to decrypt the string and it still looks like encrypted text or basically garbage. My code compiles and runs with no errors in both instances. On my development machine java version "1.2.2" Solaris VM (build Solaris_JDK_1.2.2_07a, native threads, sunwjit) is running along with jce1_2-do.tar which is the Java encryption classes. I didn't do any configuration for jce1_2-do.tar I don't know what version of Java is on the production machine. I did import my own jce1_2-do.tar on to the production. Again I didn't do any configuration for jce1_2-do.tar. I'd like to know why my encryption could work on one machine and not the other. Below is my class. //Peter adding in classes needed for communication import java.io.*; import java.lang.*; import java.util.*; import java.net.*; import java.text.*; // Because we want to use a block cipher instead of something nice like SSL3 import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; class EncryptString { private static String doAction(String action) { String secret= "foo"; Security.addProvider(new com.sun.crypto.provider.SunJCE()); BufferedReader in; PrintWriter out; String encryptedText = doEncrypt(action,Cipher.ENCRYPT_MODE,secret); // Now pad the string because server expects it padded with random memory to 4096 bytes // (yeah, this won't ever break....) while (encryptedText.length() < 4096) { encryptedText += "\0";} //Decrypt my own encryption String ServerOutput=doEncrypt(encryptedText,Cipher.DECRYPT_MODE,secret); return ServerOutput.substring(0,1024); } // Variable names are written to make sense for encrypting, but this function also decrypts based on EncOrDec public static String doEncrypt(String input,int EncOrDec,String secret) { SecretKey DESKey = null; IvParameterSpec ivs = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] secretBytes = secret.getBytes(); byte digest[] = md.digest(secretBytes); byte key[] = {digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],digest[7]}; byte iv[] = {digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],digest[14],digest[15]}; ivs = new IvParameterSpec(iv); DESKey = new SecretKeySpec(key,"DES"); } catch (java.security.NoSuchAlgorithmException e) { System.err.println("Please verify that JCE is properly installed following the directions at"); System.err.println("http://java.sun.com/products/jce/jce121_install.html or equivalent for this version"); System.err.println("it's easy to miss something - SR"); e.printStackTrace(); } try { byte[] EncryptMe = new byte[4096]; Arrays.fill(EncryptMe,(byte) 0); byte[] inputToPad = input.getBytes(); System.arraycopy(inputToPad,0,EncryptMe,0,inputToPad.length); Cipher cipher = Cipher.getInstance("DES/CFB/NoPadding"); cipher.init(EncOrDec, DESKey, ivs); byte[] cipherText = cipher.doFinal(EncryptMe); return new String(cipherText); } catch (Exception e) { System.out.println("Exception caught while (en/de)crypting!\n"); e.printStackTrace(); } return ""; } public static void main (String arguments[]) { EncryptString j = new EncryptString(); String encryptString = "HelloWorld~Variable=JohnDoe~\n"; System.out.println("String to encrypt"); System.out.println(encryptString); System.out.println("Decrypt my own encrypted String"); String returnVal = j.doAction(encryptString); System.out.println(returnVal); } } |
|
There is no answer at this time. |
|
Subject:
Re: Java encryption problem
From: sldreamer-ga on 10 May 2003 14:16 PDT |
You can determine the version of Java on the production machine by typing "java -version". |
Subject:
Re: Java encryption problem
From: eadfrith-ga on 10 May 2003 17:03 PDT |
Gadman, [I'm not a researcher and so this advice is free, and may be worth what you pay for it :-)] I'm almost certain that your problem is related to a difference in the default character encodings used under the versions of the JDK used on each machine. Consider these two lines from your code: byte[] inputToPad = input.getBytes(); return new String(cipherText); When you don't specify the character encoding the String class uses the default character encoding of the platform. The trouble with this is that certain character encodings aren't able to represent specific byte values in the character set and so they get mapped to a special "unknown" value. When you try to convert the resulting bytes back to a String you don't get what you expected! Fortunately, the "ISO8859_1" character encoding is able to represent all 255 possible byte values and so it can be safely used to do the round trip conversion. My guess is that JDK1.2.2 on Solaris uses "ISO8859_1" as the default and so you're code works here. The production machine is probably using a different version of the JDK in which the default character encoding is different, and exhibits the problem I mentioned above. Anyway, the upshot of all this is that you should be able to get your code to work on all platforms (since "ISO8859_1" is mandated to be supported on all platforms) changing two lines of your code to read: byte[] inputToPad = input.getBytes("ISO8859_1"); return new String(cipherText, "ISO8859_1"); Please let me know if this works. Also, a couple of observations on your code: while (encryptedText.length() < 4096) { encryptedText += "\0"; } This line has truly horrible performance. Use the technique you use in the doEncrypt method instead, where you use System.arraycopy. Arrays.fill(EncryptMe,(byte) 0); This line is not necessary, since Java arrays are initialized to the default value of their type upon creation, and the default value for the byte type is 0. Hope this helps. Cheers, Eadfrith |
Subject:
Re: Java encryption problem
From: gadman-ga on 10 May 2003 22:29 PDT |
Hello Eadfrith, Good find! I'm not sure this is the solution, but it seems plausible. I'm going to implement your code changes and run the code on my production server. This takes a couple of days because someone else does it. I did try out your solution on a Windows XP platform (not my production machine) where I was having similiar behaviour. Your solution worked in that case. Without your changes I got garbage, with your changes everything worked. If everything works out I would like to pay you the answer price I posted. Please provide me a method that it feasible for you. Do you have a PayPal account? Peter G. |
Subject:
Re: Java encryption problem
From: eadfrith-ga on 11 May 2003 10:46 PDT |
Hi Gadman, It makes sense that you'd have a problem on XP too since the default encoding on Windows platforms since JDK 1.1.7 is Cp1250, which definitely has the problems I mentioned. It's certainly encouraging that the use of the ISO8859_1 encoding fixes the problem there. There's really no need to pay (I don't believe it's allowed under GA rules anyway). I've been coding professionally in Java since it was released and I can't resist a challenge! I'm also hoping that providing answers will demonstrate by elligibility to become a researcher. Cheers, Eadfrith |
Subject:
Re: Java encryption problem
From: gadman-ga on 12 May 2003 19:31 PDT |
Hi Eadfrith, I tried out your solution and it kind of worked. I was able to run the modified class to successfully encrypt and decrypt my own string. I say kind of worked because the class I posted in this question was not complete. I also have a portion that sends/receives encrypted strings to another server using sockets. It doesn't work. I figure the same issue is going on and I just need to figure how to apply the same solution. Here is the complete code //Peter adding in classes needed for Pcache communication import java.io.*; import java.lang.*; import java.util.*; import java.net.*; import java.text.*; // Because we want to use a block cipher instead of something nice like SSL3 import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; class Jabberwock { private static String doAction(String action) { String server = "192.168.0.1"; String secret = "test"; Security.addProvider(new com.sun.crypto.provider.SunJCE()); BufferedReader in; PrintWriter out; String encryptedText = doEncrypt(action,Cipher.ENCRYPT_MODE,secret); // Now pad the string because the server expects it padded with random memory to 4096 bytes while (encryptedText.length() < 4096) { encryptedText += "\0";} System.out.println("About to send text with length " +encryptedText.length() ); try { // Create socket Socket s = new Socket(server, 9800); s.setSoTimeout(20000); // Timeout in 20 seconds in = new BufferedReader(new InputStreamReader( s.getInputStream())); out = new PrintWriter(s.getOutputStream(), true); out.print(encryptedText); out.flush(); System.out.println("Awaiting response\n"); char[] theResponse = new char[4096]; in.read(theResponse,0,4096); System.out.println("Got response\n"); try {s.close();} catch (Exception e) { e.printStackTrace();} // Socket closed String ServerOutput=doEncrypt(new String(theResponse),Cipher.DECRYPT_MODE,secret); return ServerOutput.substring(0,1024); } catch (IOException e) { System.err.println("Couldn't connect to server"); e.printStackTrace(); } return "-2"; } // Variable names are written to make sense for encrypting, but this function also decrypts based on EncOrDec public static String doEncrypt(String input,int EncOrDec,String secret) { SecretKey DESKey = null; IvParameterSpec ivs = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] secretBytes = secret.getBytes(); byte digest[] = md.digest(secretBytes); byte key[] = {digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],digest[7]}; byte iv[] = {digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],digest[14],digest[15]}; ivs = new IvParameterSpec(iv); DESKey = new SecretKeySpec(key,"DES"); } catch (java.security.NoSuchAlgorithmException e) { System.err.println("Please verify that JCE is properly installed following the directions at"); System.err.println("http://java.sun.com/products/jce/jce121_install.html or equivalent for this version"); System.err.println("it's easy to miss something - SR"); e.printStackTrace(); } try { byte[] EncryptMe = new byte[4096]; Arrays.fill(EncryptMe,(byte) 0); byte[] inputToPad = input.getBytes("ISO8859_1"); System.arraycopy(inputToPad,0,EncryptMe,0,inputToPad.length); Cipher cipher = Cipher.getInstance("DES/CFB/NoPadding"); cipher.init(EncOrDec, DESKey, ivs); byte[] cipherText = cipher.doFinal(EncryptMe); return new String(cipherText, "ISO8859_1"); } catch (Exception e) { System.out.println("Exception caught while (en/de)crypting!\n"); e.printStackTrace(); } return ""; } public static void main (String arguments[]) { Jabberwock j = new Jabberwock(); String serverString = "HelloWorld~variable=john~"; System.out.println(serverString); String returnVal = j.doAction(serverString); System.out.println(returnVal); } } |
Subject:
Re: Java encryption problem
From: eadfrith-ga on 12 May 2003 22:10 PDT |
Gadman, Glad to hear that the fix worked. You should be able to get your networked version working by replacing these lines: in = new BufferedReader(new InputStreamReader(s.getInputStream())); out = new PrintWriter(s.getOutputStream(), true); with these: in = new BufferedReader(new InputStreamReader(s.getInputStream(), "ISO8859_1")); out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream(), "ISO8859_1"))); Actually you don't really need a PrintWriter since a plain Writer will write a String, and you don't need to buffer the output, so you could do: Writer out = new OutputStreamWriter(s.getOutputStream(), "ISO8859_1"); I did notice a potential problem with this line in your code: in.read(theResponse,0,4096); The read method will try to read 4096 chars, but it may return before reading that many. It returns the number of chars it has actually read. So, to safely read all the chars you have to do something like this: for(int totalRead = 0; totalRead < theResponse.length; ) { int read = in.read(theResponse, totalRead, theResponse.length-totalRead); if(read == -1) { break; } totalRead += read; } Cheers, Eadfrith |
Subject:
Re: Java encryption problem
From: gadman-ga on 13 May 2003 12:53 PDT |
Hi Eadfrith, Everything completely worked! Thanks again for your help. I really wish I could reimburse (sp?) for your help. Gadman |
Subject:
Re: Java encryption problem
From: eadfrith-ga on 13 May 2003 14:51 PDT |
Gadman, That's great. Fun working with you. Cheers, Eadfrith |
Subject:
Re: Java encryption problem
From: gadman-ga on 15 May 2003 18:13 PDT |
Hi Eadfrith, I was wondering if you like to write some code for me? Please review the problem statement that I've written and come up with your price. Problem statement I have an application that has a client/server architecture. The communication between the two is set-up using ip addresses. The server is started and the client connects to the server by specifying the server ip address. This architecture runs into a problem if the meeting server is behind a network router. This is because the router has an ip address that represents computers hidden by it. If the server is behind the router its ip address is meaningless in front of the router. Thus if the client wants to connect, it cant. I realize that the network router can be configured to route certain network traffic through it to a specific computer such as a webserver. For this application though Im trying to stay away from having to reconfigure the router in order to have everything work properly. Are there ways to solve this using computer software? If there is no software solution I would appreciate suggestions on hardware solutions. I realize a solution can pose a security risk because this method can be used to side step a firewall. Below is a description of a way to solve the problem. Im not happy with the solution because it introduces a whole slew of issues that go along with hosting your own unique server on the Internet (reliability, bandwidth, system capacity, cost, administration, etc.) Possible Solution Connection Server A possible solution to the above problem is to create a software server that resides out on the general Internet and establishes and maintains a connection between the server and client(s). The following are the steps that would enable connection: - Server starts up and connects to Connection Server - Connection Server stores Server information about this connection (Unique Identifer (UID) of Server, time of connection, etc. - Client software is started and Server UID is typed into client - Client establishes connection with Connection Server stating its ip own address and the UID of the server it wants to connect to - Connection Server mediates the traffice between the client(s) to server In addition to the above architecture I would also like to be able to support multiple server/client connections using one connection server. Thus the connection server will probably have to have a client listener and a server listener. Then it would have to pass off connections to free ports on the connection server. This would require port management. For example, reclaiming free ports once a connection dies. |
If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you. |
Search Google Answers for |
Google Home - Answers FAQ - Terms of Service - Privacy Policy |