ObjectInputStream 与 CipherInputStream 冻结、挂起

发布于 2025-01-08 05:02:18 字数 2695 浏览 0 评论 0原文

我正在编写基于客户端-服务器的 Java 应用程序,但遇到了一个问题,因为在客户端和服务器中构造 ObjectInputStream 时它会挂起。

客户端:

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 有关。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦中楼上月下 2025-01-15 05:02:18

只有在发送所有信息之后才需要创建ObjectInputStream,因为ObjectInputStream的构造函数会因为需要读取标头而阻塞。

通常情况下,所有字节都已由 ObjectOutputStream 写入,但现在 CipherOutputStream 正在等待,直到它拥有完整的 16 字节块(在 AES 的情况下),然后才发送标头(最后一部分)。也许流密码模式(CTR 或 GCM)中的 AES 在这里会更有用,因为它使用每字节加密,并且能够直接发送每个字节。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文