2011-03-14 83 views
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套接字,尽管它会伤害我的辛苦工作? 预先感谢您的意见!

(顺便说一句,我的快活 - 城堡 - 包装 - 库是完全开源的,所以才让我知道如果你想存储库的URL)。

+1

可能是一个更好的问题http://codereview.stackexchange.com/ – dbyrne 2011-03-14 18:44:14

+0

我不知道这个网站。感谢您的信息,我会在那里回答我的问题。 – executifs 2011-03-14 18:47:28

+1

@Executifs,你怎么知道在中间问题上与男人作斗争。您需要一些根证书来验证服务器公钥。或者客户端已经安装了公钥? – bestsss 2011-03-14 19:36:43

回答

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和加密数据的串接作为编码消息。

这允许接收器以回收IV(如第一消息块),然后,无论处理该消息之前的消息是否被发送和接收。如果只是通过简单的“重放攻击”(攻击者发送先前发送的消息的副本),那么主动攻击者可能会在该方案中造成严重破坏。

作为一个附注,String.getBytes()new String(byte[])使用平台默认编码,这可能在客户端和服务器之间有所不同。您最好使用明确的字符集,例如UTF-8:message.getBytes("UTF-8")new String(decoded_message, "UTF-8")。一般来说,安全和自大不能很好地混合。准备抛弃你的代码。您真的应该使用标准协议(如SSL/TLS)的主要原因是安全性无法得到证实。你会告诉别人什么(例如你的老板)问你是什么让你认为协议是安全的? “Stack Overflow上的一些人告诉我这么说”?

+0

我假设OP不会传输字符串,但byte []和getBytes()仅用于测试用例。 – bestsss 2011-03-15 14:01:30

+0

非常感谢您的宝贵意见。我确实使用CBC模式,但我不知道不重复使用IV。这将被立即修复。另外,您已经说服我放弃在生产环境中使用我的代码。尽管如此,我坚信要做到这一点,所以我想我会寻找有知识的人愿意给我整个代码库的建议。再次感谢。 – executifs 2011-03-16 00:01:06

0

我只想指出,一个四不通常加密。我猜这里面没有任何伤害,但没有必要。

+0

我总是乐于学习一些东西。感谢您的附加信息。 – executifs 2011-03-14 18:59:39