2011-03-14 85 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