2013-07-27 51 views
0

我喜歡確保在應用程序中正確使用了加密部分。我打算開源這個代碼。您可以在https://gist.github.com/lameguy7quick/1e998aad673354d2661b處獲得兩個相關文件。我是否正確使用RSA加密和簽名?

我犯過什麼錯誤嗎?我知道我在撰寫本文時不瞭解HMAC。

這個想法很簡單。我加載收件人公鑰。加密隨機生成的AES密鑰。使用所述AES對消息進行編碼,然後將其填充到tcp連接中。這似乎工作正常我忽視了什麼?我有一種感覺,也許aes應該有一個隨機產生的IV,但關鍵本身是隨機生成的,所以也許我不需要?

我也使用SHA1CryptoServiceProvider我想我應該使用SHA512CryptoServiceProvider。

我簽字是否正確?它說它已簽名但我不確定是否有攻擊它

public byte[] SendMessage(byte[] recipient_pubkey, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey) 
{ 
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
    var msgid = new byte[16]; 
    rng.GetBytes(msgid); 
    using (var aes = new RijndaelManaged()) 
    { 
     byte[] rsa_aes_key; 
     RSAParameters recipient_rsap; 
     Shared.LoadKey2(Shared.pubToPem(recipient_pubkey), null, out recipient_rsap); 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      rsa.ImportParameters(recipient_rsap); 
      rsa_aes_key = rsa.Encrypt(aes.Key, false); 
     } 
     var aesmsg = EncodeMessage(recipient_pubkey, msgid, replyTo, txt, prvkey, pubkey, aes.Key, Shared.FixedIV_16bytes); 
     if (rsa_aes_key.Length + aesmsg.Length > 1024 * 15) throw new Exception(); 
     sw.WriteByte((byte)ClientServerCmd.SendMessage); 
     sw.WriteShort((short)recipient_pubkey.Length); 
     sw.Write(recipient_pubkey, 0, recipient_pubkey.Length); 
     sw.WriteShort(rsa_aes_key.Length + aesmsg.Length); 
     sw.Write(rsa_aes_key, 0, rsa_aes_key.Length); 
     sw.Write(aesmsg, 0, aesmsg.Length); 
     sw.Flush(); 
     var resp = sr.ReadByte(); 
     if (resp != (byte)ClientServerCmd.KeyLenOk) 
      throw new Exception(); 
     resp = sr.ReadByte(); 
     if (resp == (byte)ClientServerCmd.NotRegistered) 
      throw new MyException("User you're writing to does not exist"); 
     if (resp != (byte)ClientServerCmd.Success) 
      throw new Exception(); 
    } 
    return msgid; 
} 

byte[] EncodeMessage(byte[] recipient_pubkey, byte[]msgid, byte[] replyTo, string txt, byte[] prvkey, byte[] pubkey, byte[] aes_key, byte[] aes_iv) 
{ 
    if (replyTo == null) 
    { 
     replyTo = new byte[16]; 
    } 
    var txtbuf = Encoding.UTF8.GetBytes(txt); 
    var SignMessage = prvkey != null; 
    byte[] hash = null; 
    if (SignMessage) 
    { 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      RSAParameters rsap; 
      Shared.LoadKey2(Shared.prvToPem(prvkey), null, out rsap); 
      rsa.ImportParameters(rsap); 
      using (var ms = new MemoryStream()) //sign 
      { 
       ms.Write(msgid, 0, msgid.Length); 
       ms.Write(replyTo, 0, replyTo.Length); 
       ms.WriteShort((short)txtbuf.Length); 
       ms.Write(txtbuf, 0, txtbuf.Length); 
       ms.WriteShort((short)pubkey.Length); 
       ms.Write(pubkey, 0, pubkey.Length); 
       ms.WriteShort((short)recipient_pubkey.Length); 
       ms.Write(recipient_pubkey, 0, recipient_pubkey.Length); 
       ms.Position = 0; 
       hash = rsa.SignData(ms, new SHA1CryptoServiceProvider()); 
      } 
     } 
    } 
    byte[] c1; 
    using (var ms1 = new MemoryStream()) 
    using (var ms = new BZip2OutputStream(ms1)) 
    { 
     ms.Write(txtbuf, 0, txtbuf.Length); 
     ms.Close(); 
     c1 = ms1.ToArray(); 
    } 
    var compressText = c1.Length < txtbuf.Length; 
    byte[] aesmsg; 
    byte[] aeskey; 
    using (var aes = new RijndaelManaged()) 
    { 
     aeskey = aes.Key; 
     aes.IV = Shared.FixedIV_16bytes; 
     using (MemoryStream msEncrypt = new MemoryStream()) 
     { 
      using (var encryptor = aes.CreateEncryptor(aes_key, aes_iv)) 
      using (CryptoStream sw2 = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
      { 
       sw2.WriteByte((Byte)((compressText ? 1 : 0) | (SignMessage ? 2 : 0))); 
       sw2.Write(msgid, 0, msgid.Length); 
       sw2.Write(replyTo, 0, replyTo.Length); 
       if (compressText) 
       { 
        sw2.WriteShort((short)c1.Length); 
        sw2.Write(c1, 0, c1.Length); 
       } 
       else 
       { 
        sw2.WriteShort((short)txtbuf.Length); 
        sw2.Write(txtbuf, 0, txtbuf.Length); 
       } 
       if (SignMessage) 
       { 
        sw2.WriteShort((short)pubkey.Length); 
        sw2.Write(pubkey, 0, pubkey.Length); 
        sw2.WriteShort((short)hash.Length); 
        sw2.Write(hash, 0, hash.Length); 
       } 
      } 
      msEncrypt.Flush(); 
      aesmsg = msEncrypt.ToArray(); 
     } 
    } 
    return aesmsg; 
} 
+0

應該已經遷移到代碼審查。 –

+0

你有沒有理由不能只使用TLS? – ntoskrnl

回答

0

固定的IV是肯定不正確的。

IV對於AES CBC不應該是可預測的。通常情況下,您可以隨意添加密文。

一個mac對於避免選擇密文攻擊非常重要,你正在讀寫你自己的格式,你必須擔心操縱你的密文允許暴露一些東西,你的aes代碼可能會拋出一個可以使用的填充異常通過發送修改後的密文到您的接收機來恢復明文。

這是很好的,你的代碼將是開源的,打開它的分析和補丁,但你應該知道applying cryptography correctly is difficult,容易犯錯誤。

如果你可以適應一個高層次的庫,比如Keyczar(我把它移植到c#),那麼你將會變得更好,儘管沒有什麼是完美的。

+0

如果AES密鑰隨機分配給每個*消息*,您確定需要獨特的IV嗎?我不明白維基的HMAC代碼,但這會工作嗎? (錯誤的僞代碼)'var hmac = SHA512CryptoServiceProvider; hmac.write(rsa_aes_key); hmac.write(aesmsg); var hmac2 = ...; hmac2.write(HMAC); hmac2.write(rsa_aes_key);返回hmac2'。我想我正在做的是散列rsa鍵和aes消息來獲得sha哈希。然後,我將這個結果和rsa密鑰散列到最終的散列結果中。這聽起來正確 – user28759

+0

你應該真的閱讀文章。 – jbtule

+0

我沒有找到任何東西,當我搜索pss。我相信.net確實包括填充,所以我不相信我需要實現OAEP?我遵循的hmac想法正確地遵循了http://www.thoughtcrime.org/blog/the-cryptographic-doom-principle/(我做了#3)。 – user28759

相關問題