Google Answers Logo
View Question
 
Q: Java encryption problem ( No Answer,   9 Comments )
Question  
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);
    }

}
Answer  
There is no answer at this time.

Comments  
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 can’t.
 
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 I’m 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. I’m 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.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

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 Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy