1

I'm programming client-server based Java application and I've got a problem, because it hangs when constructing ObjectInputStream both in client and server.

Client:

Socket socket = new Socket("localhost", 9999);

outCiph = new CipherOutputStream(socket.getOutputStream(), AES.getEncryptCipher("key"));
out = new ObjectOutputStream(outCiph);
inCiph = new CipherInputStream(socket.getInputStream(), AES.getDecryptCipher("key"));
in = new ObjectInputStream(inCiph);

try
{
String text = "test!";

out.writeObject(text);
out.flush();

if (out != null)
out.close();

if (in != null)
in.close();
}
catch (IOException ex)
{
System.err.println(ex.toString());
}

Server:

ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();

outCiph = new CipherOutputStream(socket.getOutputStream(), AES.getEncryptCipher("key"));
out = new ObjectOutputStream(outCiph);
inCiph = new CipherInputStream(socket.getInputStream(), AES.getDecryptCipher("key"));
in = new ObjectInputStream(inCiph);

try
{
String rec = (String) in.readObject();
System.out.println("Received from client: " + rec);

if (out != null)
out.close();

if (in != null)
in.close();

}
catch (IOException ex)
{
System.err.println(ex.toString() + " in start()");
}
catch (ClassNotFoundException ex)
{
System.err.println(ex.toString());
}

AES:

// I'm not author of generateKey method so I've no idea if is it correct
private static byte[] generateKey(String pass) throws UnsupportedEncodingException, NoSuchAlgorithmException
{
MessageDigest sha = MessageDigest.getInstance("SHA-256");
byte[] passBytes = pass.getBytes("ASCII");
byte[] sha256Bytes = sha.digest(passBytes);


byte[] key = new byte[16];
int j = 0;
for (int i = 0; i < sha256Bytes.length; i++)
{
    if (i % 2 == 0)
    {
    key[j] = sha256Bytes[i];
    j++;
    }
}
return key;
}

public static Cipher getEncryptCipher(String pass)
{
try
{
    SecretKeySpec skeySpec = new SecretKeySpec(generateKey(pass), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    return cipher;
}
catch (Exception ex) // just for clarity
{
    Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}

public static Cipher getDecryptCipher(String pass)
{
try
{
    SecretKeySpec skeySpec = new SecretKeySpec(generateKey(pass), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    return cipher;
}
catch (Exception ex) // just for clarity
{
    Logger.getLogger(AES.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}

When I don't use CipherInput/OutputStream everything works fine so the problem is somehow related with CipherInput/OutputStream.

user1227115
  • 843
  • 1
  • 8
  • 11
  • 1
    What kind of Cipher does DES.getEncryptCipher return? Could you print out the algorithm and state of the returned cipher? It might be that you need a Cipher that performs padding, otherwise it may be waiting for exactly N * [block size] bytes to finish computation. *Note that DES is not safe, use AES* – Maarten Bodewes Feb 23 '12 at 00:03
  • DES was just example, I was testing another class. The primary encryption class is the one above, not DES. – user1227115 Feb 23 '12 at 00:18
  • Ok, but do use `"AES/CBC/PKCS5Padding"` for the Cipher as just `"AES"` defaults to `"AES/ECB/PKCS5Padding"`, at least for the Sun/Oracle provider, and ECB is unsafe for non-randomized bytes such as headers and objects. – Maarten Bodewes Feb 23 '12 at 01:14

1 Answers1

1

You need to create the ObjectInputStream only after you've send all the information over, because the constructor of ObjectInputStream blocks because it needs to read the header.

Normally, all the bytes would have been written by the ObjectOutputStream, but now the CipherOutputStream is waiting until it has a full 16 byte block (in the case of AES) before it sends the (last part of the) header over. Maybe AES in stream cipher mode (CTR or GCM) would be more useful here as it uses per byte encryption, and would be able to directly send each byte.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • There are some hacks you can perform, such as writing a byte array of bytes directly after creating the constructor, and then flush the ObjectOutputStream. Of course, you need to read those spurious 16 bytes at the other side as well. – Maarten Bodewes Feb 23 '12 at 00:48