Possible bug in JCE 1.2

Farzad Buxey (farzad@engr.csufresno.edu)
Sat, 09 May 1998 18:26:00 -0700

Date: Sat, 09 May 1998 18:26:00 -0700
From: Farzad Buxey <farzad@engr.csufresno.edu>
To: java-security-bugs@puffin.eng.sun.com, java-security@web1.javasoft.com
Subject: Possible bug in JCE 1.2

This is a multi-part message in MIME format.
--------------CC69C630B61D5FC4DB4C8E42
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi
This might be a possible bug in JCE 1.2 or it might be my ignorance,
but here is the situation.

I have a client-server socket set up
1. the client reads a file
2. creates a socket connection to the server
3. creates a cipherOutputstream on the socket's outputStream
and send the file's contents on it.
at the server end
4. the server has a cipherInputStream which reads the transmitted data
here is where the problem occurs
a. the first read returns only 504 bytes
seeing the traces, I've noticed that the packet sizes are 512, so is
the first packet not containing the complete data ? or is the TCP
packet not passed correctly to the higher level.
b. read never returns a -1 to signal end of transmission. hence the
socket sits in an infinite loop waiting to the last packet.

here is the run on the server side

In initialization of Encrypt/Decrypt
Finished inintialization of Encrypt/Decrypt
Got new length:10248
reading ciphered input stream of length:10248
ret:504 off:504 length:9744
ret:512 off:1016 length:9232
ret:512 off:1528 length:8720
ret:512 off:2040 length:8208
ret:512 off:2552 length:7696
ret:512 off:3064 length:7184
ret:512 off:3576 length:6672
ret:512 off:4088 length:6160
ret:512 off:4600 length:5648
ret:512 off:5112 length:5136
ret:512 off:5624 length:4624
ret:512 off:6136 length:4112
ret:512 off:6648 length:3600
ret:512 off:7160 length:3088
ret:512 off:7672 length:2576
ret:512 off:8184 length:2064
ret:512 off:8696 length:1552
ret:512 off:9208 length:1040
ret:512 off:9720 length:528
ret:512 off:10232 length:16

I have attched the server,client and a common Encryption/Decryption
source code file that should encompass the functionality.

could you please tell me if I am doing something wrong or is there a bug
:)

I have also been benchmarking the JCE across a dial-up connection,
permemant internet connections, etc ...it takes about 300 milli seconds
to encrypt/decrypt ..thats fantastic...bravo to you..

thanks

farzad
--------------CC69C630B61D5FC4DB4C8E42
Content-Type: java/*; name="Client.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="Client.java"

import java.net.*;
import java.io.*;

class Client
{
Socket m_sock=null;
DataOutputStream out;
DataInputStream in ;
String IP,szFileName;
byte b[]=null;
EncryptDecrypt e = null;

public Client(String a[])
{
IP=new String(a[0]);
szFileName=new String(a[1]);
}

public void do_work()
{
try
{
if(m_sock==null)
m_sock = new Socket(IP,5555);
m_sock.setTcpNoDelay(false);
out = new DataOutputStream(m_sock.getOutputStream());
in = new DataInputStream(m_sock.getInputStream());
byte ret[],dec[];

System.out.println("In mode: cipher streams");
out.writeLong(e.getOutputSize(true,b.length));
e.cStream_write(m_sock.getOutputStream(),b);
long len = in.readLong();
dec = e.cStream_read(m_sock.getInputStream(),e.getOutputSize(false,(int)len));
EncryptDecrypt.compare(b,dec);
exit();
}
catch(Exception e){e.printStackTrace();System.exit(0);}
}

private void exit()
{
try
{
m_sock.close();
in.close();
out.close();
m_sock=null;
}
catch(Exception e){e.printStackTrace();m_sock=null;}
}

public byte [] readFile()
{
try
{
File f = new File(szFileName);
FileInputStream fin = new FileInputStream(f);
long length = f.length();
byte b[] = new byte [(int)length];
fin.read(b,0,b.length);
fin.close();
System.out.println("Read File of length="+ length);
return b;
}
catch(Exception e){e.getMessage();}
return null;
}


public void run()
{
e = new EncryptDecrypt();
b = readFile();
do_work();
}

public static void main(String arg[])
{
String a[] = new String [3];
Client c ;
if(arg.length != 2)
{
a[0]=new String("127.0.0.1");
//a[0]=new String("129.8.115.124");
a[1]=new String("data");
c = new Client(a);
}
else
c = new Client(arg);
c.run();
}

}

--------------CC69C630B61D5FC4DB4C8E42
Content-Type: java/*; name="EchoServer.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="EchoServer.java"

import java.net.*;
import java.io.*;

public class EchoServer implements Runnable
{
ServerSocket server = null;
Thread t;

public EchoServer()
{
try
{
server = new ServerSocket(5555);
t = new Thread(this);
t.start();
System.out.println("Started Echo Server");
}
catch (Exception e){e.printStackTrace();System.exit(0);}

}

public void run()
{
while(true)
{
try
{
Socket m_sock = server.accept();
new connection(m_sock);
System.out.println("Got new Connection");
}
catch (Exception e){e.printStackTrace();}
}
}


public static void main(String args[])
{
new EchoServer();
}
}

class connection extends Thread
{
Socket m_sock;
DataInputStream inputSocket= null ;
DataOutputStream outputSocket= null ;
byte data[];
EncryptDecrypt e = null;

public connection(Socket m_sock)
{
super("Echo Server");
this.m_sock = m_sock;
this.start();
}

public void run()
{
try
{
m_sock.setTcpNoDelay(false);
inputSocket = new DataInputStream(m_sock.getInputStream());
outputSocket = new DataOutputStream(m_sock.getOutputStream());
System.out.println("In mode: cipher streams");
if(e==null)
initEncDec();
long len = inputSocket.readLong();
byte dec[] = e.cStream_read(m_sock.getInputStream(),e.getOutputSize(false,(int)len));
outputSocket.writeLong((long)e.getOutputSize(true,dec.length));
e.cStream_write(m_sock.getOutputStream(),dec);
}
catch (Exception e){e.printStackTrace();}
}

public void initEncDec()
{
e = new EncryptDecrypt();
}

}
--------------CC69C630B61D5FC4DB4C8E42
Content-Type: java/*; name="EncryptDecrypt.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="EncryptDecrypt.java"

import javax.crypto.*;
import java.security.*;
import java.io.InputStream;
import java.io.OutputStream;

public class EncryptDecrypt
{
Key key;
Cipher cipher;

public EncryptDecrypt()
{
try
{
System.out.println("In initialization of Encrypt/Decrypt");
Provider sunJCE = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunJCE);
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
//This doesn't work as specified in the guide and doc
//KeyGenerator keyGen = KeyGenerator.getInstance("DES/ECB/PKCS5Padding");
String seed = new String("benchmarking JCE 1.2");
byte b[] = seed.getBytes();
keyGen.init(new SecureRandom(b));
key = keyGen.generateKey();
cipher = Cipher.getInstance(new String("DES"));
System.out.println("Finished inintialization of Encrypt/Decrypt");
}
catch(Exception e){System.out.println(e.getMessage());}
}

public byte[] encrypt(byte b[])
{
try
{
System.out.println("Encrypt/Decrypt: Encrypting Data");
cipher.init(Cipher.ENCRYPT_MODE,key);
byte enc[] = cipher.doFinal(b);
return enc;
}
catch(Exception e){e.printStackTrace();}
return null;
}

public byte[] decrypt(byte b[])
{
try
{
System.out.println("Encrypt/Decrypt: Decrypting Data");
cipher.init(Cipher.DECRYPT_MODE,key);
byte dec[] = cipher.doFinal(b);
return dec;
}
catch(Exception e){e.printStackTrace();}
return null;
}

// mode should be either : Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
public byte[] cStream_read(InputStream in,long len)
{
try
{
System.out.println("reading ciphered input stream of length:" + len);
//cipher.init(Cipher.DECRYPT_MODE,key);
CipherInputStream cin = new CipherInputStream(in,cipher);
//byte b[] = new byte[(int)len];
byte b[] = new byte[10240];
int off = 0,ret = 0;
while(ret != -1)
{
//the length can be specified as anything , the packet still come in sizes of
//512
//ret = cin.read(b,off,Math.min(512,(int)len));
ret = cin.read(b); //thrying this out

off += ret;
len -= ret;
System.out.println("ret:" + ret + " off:" + off + " length:" + len);
}
System.out.println("Finished reading ciphered input stream");
return b;
}
catch(Exception e){e.printStackTrace();}
return null;
}

public boolean cStream_write(OutputStream out,byte b[])
{
try
{
System.out.println("Sending ciphered output stream");
//cipher.init(Cipher.ENCRYPT_MODE,key);
CipherOutputStream cout = new CipherOutputStream(out,cipher);
cout.write(b,0,b.length);
cout.flush();
System.out.println("Finished Sending ciphered output stream of length:" + b.length);
return true;
}
catch(Exception e){e.printStackTrace();}
return false;
}

public int getOutputSize(boolean mode,int length)
{
try
{
if(mode)
cipher.init(Cipher.ENCRYPT_MODE,key);
else
cipher.init(Cipher.DECRYPT_MODE,key);
System.out.println("Got new length:" + cipher.getOutputSize(length));
return cipher.getOutputSize(length);
}
catch(Exception e){e.printStackTrace();}
return -1;
}

public static boolean compare(byte b1[],byte b2[])
{
if(b1.length != b2.length)
{
System.out.println("Compare falied ! Got wrong number of bytes");
return false;
}
boolean bCompare = true;
for(int i=0;i<b1.length;i++)
{
if(b1[i] != b2[i])
{
bCompare = false;
System.out.println("Compare falied ! byte arrays are not the same");
break;
}
}
if(bCompare)
System.out.println("Compare finished ! byte arrays are the same");
return bCompare;
}

public static void main(String a[])
{
EncryptDecrypt e = new EncryptDecrypt();
String s = new String("mary had a little lamb, her fleet was bright as snow!!");
byte b[] = s.getBytes();
System.out.println("input:" + (new String(b)));
byte enc[] = e.encrypt(b);
System.out.println("encrypted:" + (new String(enc)).trim());
byte dec[] = e.decrypt(enc);
System.out.println("decrypted:" + (new String(dec)).trim());
e.compare(b,dec);
}
}
--------------CC69C630B61D5FC4DB4C8E42--