2012-02-22 76 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 /輸出流。

+1

DES.getEncryptCipher返回什麼樣的密碼?你能打印出算法和返回密碼的狀態嗎?這可能是因爲您需要一個執行填充的密碼,否則它可能正在等待N * [塊大小]字節完成計算。 *請注意,DES是不安全的,使用AES * – 2012-02-23 00:03:15

+0

DES只是一個例子,我正在測試另一個類。主加密類是上面的,而不是DES。 – user1227115 2012-02-23 00:18:57

+0

好的,至少對Sun/Oracle提供商來說,確實使用''AES/CBC/PKCS5Padding'作爲密碼,'AES'默認爲''AES/ECB/PKCS5Padding'「,而ECB是不安全的用於非隨機化的字節,如標題和對象。 – 2012-02-23 01:14:02

回答

1

只有當您發送全部信息結束後,您才需要創建ObjectInputStream,因爲ObjectInputStream的構造函數因爲需要讀取標頭而被阻塞。

通常情況下,所有的字節都將被ObjectOutputStream寫入,但是現在CipherOutputStream正在等待,直到它有一個完整的16字節塊(在AES的情況下),然後才發送(最後一部分)頭。也許AES在流密碼模式(CTR或GCM)中會更有用,因爲它使用每字節加密,並且能夠直接發送每個字節。

+0

有一些你可以執行的竅門,比如在創建構造函數後直接寫入字節的字節數組,然後刷新ObjectOutputStream。當然,你也需要在另一端讀取那些虛假的16字節。 – 2012-02-23 00:48:33

+0

如果您對問題進行了跟蹤,user1227115,或者點擊了接受按鈕,那就太好了。 – 2012-03-08 20:05:29

相關問題