【问题标题】:Java: encrypted data over SocketJava:通过 Socket 加密数据
【发布时间】:2017-06-07 16:00:34
【问题描述】:

我正在尝试通过 Socket 发送加密数据。

我搭建了一个Server和一个Client,可以成功的交换数据,典型的(这是一个client的例子,在server上也一样)

int count = 0;
byte[] buffer = new buffer[4096];

while ((count = fileInputStream.read(buffer)) >= 0) 
{
    outToServer.write(buffer, 0, count);
    outToServer.flush();
}

我还有一个方法,它接受 byte[] 和一个密钥,并返回一个使用 AES 128bit 加密的 byte[]。另一种方法以相同的方式解密。

现在,我将如何通过Socket 发送加密数据? 我遇到了很多问题,因为加密缓冲区的大小与普通缓冲区不同。例如,我从文件中加载4096 字节,加密它们并以4112 结束。 这个数字不是最适合转移的。我无法将其分解,因为显然服务器需要“完整”读取块 - 因为它们已加密 - 否则它将无法解密。

即使我先加密整个文件,然后发送,我仍然需要逐块加密,当我读回解密时,这些块会被分解。

很明显,服务器无法知道加密块的填充大小(在接收任何内容之前),因此它总是一次读取 4096 个字节。

我能做什么?

【问题讨论】:

  • 您所说的“最佳转移数量”是什么意思?
  • 指定负载大小。如果需要,您的服务器可以调整缓冲区,或者简单地读取多个0-4096 块,直到获得整个有效负载。 4096 是单次读取可以读取的数据量,这并不意味着所有有效负载都必须在该范围内。
  • 看看CipherInputStreamCipherOutputStream。不要在循环内部冲洗。
  • 注意“不是最适合传输”是错误的。无论如何,TCP 都会以任何它喜欢的方式对数据进行分段。不要担心试图超越 TCP。你不会的。
  • @AJNeufeld 你不需要DataOutputStream。对于任何输出流,OutputStream.write() 已经这样做了。

标签: java sockets encryption cryptography


【解决方案1】:

如果您打算以 4096 字节块的形式发送数据,则可以只以稍小的块(可能是 4095 字节,如果您的填充按我认为的方式工作)读取未加密的数据,然后通过网络发送填充的 4096 字节块。

确实,未加密的明文和加密的密文的大小不一样,但是加密任何两个等长的明文应该会产生等长的密文。如果您总是加密相同大小的明文,那么您通过套接字发送的加密密文的大小应该始终相同。因此,作为上述的替代方案,您可以继续读取 4096 块的文件,并告诉接收缓冲区期望 4112 字节。

您没有提及您正在使用哪种 AES 模式(我怀疑是 CBC)或您正在使用哪种填充方案(我怀疑是 PKCS#7),所以我不确定填充在您的方案,但我猜您的方案正在被填充到下一个 16 字节的倍数(如果它已经是 16 的倍数,则添加完整的 16 字节)。所以你应该能够以 4095 字节的块读取文件,或者最坏的情况是 4080 字节,它们将被填充到 4096。

我还鼓励您切换到 GCM 模式,该模式 (1) 不需要填充,并且 (2) 除了加密之外还提供身份验证。

【讨论】:

  • GCM 不填充加密,但 JCA API 将 authtag 附加到有效扩展密文的密文中。 CBC 通常要求您将 IV 与密文一起发送,而 GCM 可以使用不需要传输的计数器,当且仅当您的数据传输是有序且可靠的,如 TCP 而不是 UDP。跨度>
【解决方案2】:

我能做什么?

你不需要做任何事情。无论您发送什么,TCP 都会对其进行分段,而 IP 会以任何喜欢的方式对其进行分组。在接收端 TCP 是一个字节流,而不是一个消息系统。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-27
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    相关资源
    最近更新 更多