【问题标题】:Peer review for a cryptographic key exchange加密密钥交换的同行评审
【发布时间】:2011-03-14 18:39:16
【问题描述】:

过去几天我一直在玩 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,请告诉我。)

【问题讨论】:

  • 对于codereview.stackexchange.com来说可能是一个更好的问题
  • 我不知道这个网站。谢谢你的信息,我会在那里回答我的问题。
  • @Executifs,你怎么知道和中间人打架。您需要一些根证书来验证服务器公钥。还是客户端已经安装了公钥?
  • 以上都不是:MITM 尚未被确定为对我的应用程序的威胁。被动窃听是这里唯一的目标。不过,预安装公钥是一个可行的选择。
  • @Executifs,如果你能确保非常可信的连接(没有 DNS 攻击?),你应该没问题。虽然交换 sym 的方式更简单。密钥只是一个 SSL 套接字(通常是 https)和交换,继续使用 AES/RCx/whatever

标签: java cryptography rsa aes diffie-hellman


【解决方案1】:

(您的协议中没有 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")

一般来说,安全感和狂妄自大不能很好地融合在一起。准备好放弃你的代码。您真正应该使用 SSL/TLS 等标准协议的主要原因是无法证明安全性。你会告诉某人(例如你的老板)什么让你认为协议是安全的? “Stack Overflow 上的某个人告诉我的”?

【讨论】:

  • 我假设 OP 不传输字符串,但 byte[] 和 getBytes() 仅用于测试用例。
  • 非常感谢您的宝贵建议。我确实在使用 CBC 模式,但我不知道不重用 IV。这将立即修复。此外,您已经说服我放弃在生产环境中使用我的代码。不过,我坚持要深入了解这一点,所以我想我会寻找愿意就整个代码库给我建议的知识渊博的人。再次感谢。
【解决方案2】:

我只想指出 IV 通常不加密。我想这没什么坏处,但没必要。

【讨论】:

  • 我总是很高兴能学到一些东西。感谢您提供更多信息。
猜你喜欢
  • 2018-02-03
  • 1970-01-01
  • 2019-08-02
  • 2011-07-11
  • 2023-04-07
  • 1970-01-01
  • 2012-05-01
  • 2012-06-13
  • 1970-01-01
相关资源
最近更新 更多