2012-02-22 2 views
1

Я программирую Java-приложение на основе сервера на основе сервера, и у меня есть проблема, потому что он зависает при построении ObjectInputStream как на клиенте, так и на сервере.ObjectInputStream с CipherInputStream замораживание, зависание

Клиент:

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()); 
} 

Сервер:

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; 
} 

Когда я не использую CipherInput/OutputStream все в порядке, так что проблема как-то связана с работы CipherInput/OutputStream.

+1

Какой шифр возвращает DES.getEncryptCipher? Не могли бы вы распечатать алгоритм и состояние возвращаемого шифра? Возможно, вам понадобится шифр, который выполняет прописку, иначе он может ожидать, что именно N * [размер блока] байт завершит вычисление. * Обратите внимание, что DES небезопасен, используйте AES * –

+0

DES был просто примером, я тестировал другой класс. Основной класс шифрования - это выше, а не DES. – user1227115

+0

Хорошо, но используйте '' AES/CBC/PKCS5Padding ''для Cipher как просто« AES »' по умолчанию для «AES/ECB/PKCS5Padding» ', по крайней мере для поставщика Sun/Oracle, и ECB небезопасен для не рандомизированных байтов, таких как заголовки и объекты. –

ответ

1

Вам необходимо создать ObjectInputStream только после того, как вы отправите всю информацию, потому что конструктор ObjectInputStream блокирует, потому что ему нужно прочитать заголовок.

Как правило, все байты были бы записаны ObjectOutputStream, но теперь CipherOutputStream ожидает, пока он не будет иметь полный 16-байтовый блок (в случае AES), прежде чем он отправит заголовок (последняя часть) , Возможно, AES в режиме потокового шифрования (CTR или GCM) будет более полезен здесь, поскольку он использует шифрование по байтам и сможет напрямую отправлять каждый байт.

+0

Есть некоторые хаки, которые вы можете выполнить, например, написать байтовый массив из байт непосредственно после создания конструктора, а затем очистить объект ObjectOutputStream. Конечно, вам нужно прочитать эти паразитные 16 байт на другой стороне. –

+0

Было бы неплохо, если бы вы ответили на ваши вопросы, user1227115, или, может быть, нажали кнопку accept. –

Смежные вопросы