对密码密钥交换的同行评审

时间:2011-03-14 18:39:17

标签: java cryptography rsa aes diffie-hellman

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

2 个答案:

答案 0 :(得分:2)

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

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

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

  1. 为每条消息选择一个新的随机IV(通过加密强RNG,例如java.security.SecureRandom);
  2. 将IV和加密数据的串联作为编码消息发送。
  3. 这允许接收器恢复IV(作为第一个消息块),然后处理该消息,而不管先前的消息是否被发送和接收。同样,如果只是通过简单的“重放攻击”(攻击者发送先前发送的消息的副本),主动攻击者可能会对该方案造成严重破坏。

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

    一般来说,安全和狂妄自然并不好。准备放弃你的代码。您真正应该使用标准协议(如SSL / TLS)的主要原因是无法证明安全性。你会告诉某人(例如你的老板)问你什么让你觉得协议是安全的? “Stack Overflow上的一些人告诉过我”?

答案 1 :(得分:0)

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