java - 加密 key 交换的同行评审

标签 java cryptography rsa aes diffie-hellman

过去几天我一直在研究 Bouncy CaSTLe (java),我已经达到了我相信我可以通过 Diffie-Hellman 交换安全地交换 key 的地步。

在阅读了许多强调正确实现加密交换的困难的帖子后,我希望您对我的工作提出诚实的意见。 所有底层密码操作都基于 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,请告诉我。)

最佳答案

(你们的协议(protocol)没有Diffie-Hellman,只有RSA和对称加密。)

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

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

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

这允许接收方恢复 IV(作为第一个消息 block )然后处理消息,而不管之前的消息是否已发送和接收。同样,如果仅通过简单的“重放攻击”(攻击者发送先前发送的消息的副本),主动攻击者可能会对该方案造成严重破坏。

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

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

关于java - 加密 key 交换的同行评审,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5302888/

相关文章:

c# - RSACryptoServiceProvider 和 RSAPKCS1Signatureformatter 之间的不同

java - 用于测试目的的 SSL 连接

java - 当线程在 Java 中死亡时 ThreadPoolExecutor 会发生什么

c# - NSec.Cryptography 使用 ChaCha20Poly1305 和 SharedSecret 进行加密和解密

Android 创建 RSA 1024 .NET 兼容 key

cryptography - Linux内核是否支持RSA加密/解密?

python - Python中的RSA加密和解密

java - 为什么我有 javax.servlet.UnavailableException : CrawlServlet for my Filter?

java - 64 位 JVM 的最大可能堆大小是多少?

Python 开源密码学工具包