2

在过去的几天里,我一直在玩 Bouncy Castle (java),并且我已经达到了我相信我可以通过 Diffie-Hellman 交换安全地交换密钥的地步。

在阅读了许多强调正确实施加密交换困难的帖子后,我希望您能对我的工作发表诚实的看法。所有底层密码操作都基于 Bouncy Castle,因此可能被认为是可靠的。

    String message = "Hello World";

    AESCipher aes_client = new AESCipher(256);
    RSACipher rsa_server = new RSACipher(2048);

    // (Public key sent over the wire)
    RSACipher rsa_client = new RSACipher(rsa_server.getPublicKey().getModulus(),
                                         rsa_server.getPublicKey().getExponent());

    // The client encodes his AES key with the RSA public key:
    byte[] aes_key = rsa_client.encode(aes_client.getKeyBytes());
    byte[] aes_iv = rsa_client.encode(aes_client.getInitializationVector());

    // (Data sent back over the wire)
    byte[] decoded_aes_key = rsa_server.decode(aes_key);
    byte[] decoded_aes_iv = rsa_server.decode(aes_iv);

    // The server creates an AES server which uses the client key:
    AESCipher aes_server = new AESCipher(decoded_aes_key, decoded_aes_iv);

    byte[] encoded_message = aes_client.encode(message.getBytes());
    byte[] decoded_message = aes_server.decode(encoded_message);

    System.out.println(new String(decoded_message));

这种交换可以被认为是安全的吗?我是否应该坚持使用 SSL 套接字,尽管我的辛勤工作会受到伤害?提前感谢您的意见!

(顺便说一句,我的 Bouncy-Castle-Wrapping-Library 是完全开源的,所以如果你想要存储库的 URL,请告诉我。)

4

2 回答 2

2

(您的协议中没有 Diffie-Hellman,只有 RSA 和对称加密。)

第一个基本说明是您的协议容易受到主动攻击。“Man-in-the-middle”是经典(攻击者截获公钥,用自己的代替)。此外,您只有对称加密,但没有 MAC。假设您的攻击模型仅针对被动攻击者;大多数时候,至少可以说,这是一个非常大胆的假设。实际上,我很难想象这种情况会适用:窃听者可以查看传输的字节但无法发送自己的消息。除非您在经过身份验证的隧道中运行整个过程并进行完整性检查(SSL 有一种模式可以做到这一点,但这种方式会失败)。

您正在加密不需要的 IV(IV 不是密钥,否则它将被称为“密钥”,而不是 IV)。您需要的 IV 是为每条加密消息随机生成的。假设您使用 CBC 模式,则可以将消息中的最后一个加密块用作下一条消息的 IV。然而,为具有相同对称加密密钥的两条不同消息重用 IV 将是致命的。由于 Bouncy Castle 没有任何名为 的类AESCipher,因此您的示例代码不会告诉我们您是否正在使用具有正确链接模式和正确 IV 管理的 AES。另请注意,仅当消息按顺序发送且没有消息丢失时,重用上一条消息中的最后一个加密块才有效。一个更强大的解决方案是:

  1. 为每条消息选择一个新的随机 IV(通过加密强的 RNG,例如java.security.SecureRandom);
  2. 将 IV 和加密数据的连接作为编码消息发送。

这允许接收方恢复 IV(作为第一个消息块),然后处理该消息,而不管之前的消息是否已发送和接收。再一次,一个活跃的攻击者可能会在该方案中造成严重破坏,只要通过简单的“重放攻击”(攻击者发送先前发送的消息的副本)。

作为旁注,String.getBytes()new String(byte[])使用平台默认编码,这可能在客户端和服务器之间有所不同。最好使用显式字符集,例如 UTF-8:message.getBytes("UTF-8")new String(decoded_message, "UTF-8").

Generically speaking, security and hubris do not mix well. Be prepared to ditch your code. The main reason why you really should use standard protocols such as SSL/TLS is that security cannot be proven. What would you tell to someone (e.g. your boss) asking you what makes you think that the protocol is secure ? "Some guy on Stack Overflow told me so" ?

于 2011-03-15T11:08:18.317 回答
0

我只想指出 IV 通常不加密。我想这没有害处,但没有必要。

于 2011-03-14T18:51:59.230 回答