2011-12-07 55 views
6

這是我的第一篇文章,所以希望我沒有錯過任何重要的東西。我正在C#中做一個項目,我需要使用公鑰/私鑰加密來加密郵件,然後通過SSL連接發送。RSA加密大數據在C#

根據文檔,我選擇使用RSACryptoService,這是唯一用於加密數據的非對稱加密方案。問題在於我遇到了很多問題。 (我想做對稱加密,但這不是我的老師想讓我做的事情,根據他的說法,應該很容易確定一個塊的大小,然後它應該爲你做所有的工作。)好吧,到目前爲止沒有運氣,我已經嘗試了一些不同的方法,但現在我回到基礎,再次努力,這是我當前的代碼:

public string[] GenerateKeysToStrings(string uniqueIdentifier) 
    { 
     string[] keys; 
     using (var rsa = new RSACryptoServiceProvider(4096)) 
     { 
      try 
      { 
       string privateKey = rsa.ToXmlString(true); 
       string publicKey = rsa.ToXmlString(false); 

       this.pki.StoreKey(publicKey, uniqueIdentifier); 

       keys = new string[2]; 
       keys[0] = privateKey; 
       keys[1] = publicKey; 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return keys; 
    } 

正如你所看到的,我生成密鑰和我mimmick一個PKI通過發送公鑰到一個簡單的類來存儲它,然後將私鑰寫入文件 (請注意,我也有另一種方法可以完成相同的工作,但將它存儲到數組中,僅僅是因爲我想測試並簡化的事情,因爲我得到No such key exceptions,有時加密異常,當我這樣做前充足的,所以想通過簡單地貯存rsa.ToXmlString串,如在陣列中的字符串,但是沒有運氣簡化它)

現在我有一個加密和解密方法如下:

public string Encrypt(string keyString, string message) 
    { 
     string encryptedMessage; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Load the key from the specified path 
       var encryptKey = new XmlDocument(); 
       encryptKey.Load(@"C:\Test\PrivateKeyInfo.xml"); 
       rsa.FromXmlString(encryptKey.OuterXml); 


       //// Conver the string message to a byte array for encryption 
       //// var encoder = new UTF8Encoding(); 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       byte[] dataToEncrypt = byteConverter.GetBytes(message); 

       byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false); 

       //// Convert the byte array back to a string message 
       encryptedMessage = byteConverter.GetString(encryptedData); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return encryptedMessage; 
    } 

解密:

public string Decrypt(string keyString, string message) 
    { 
     string decryptedText; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Loads the keyinfo into the rsa parameters from the keyfile 
       /* 
       var privateKey = new XmlDocument(); 
       privateKey.Load(keyString); 
       */ 
       rsa.FromXmlString(keyString); 

       //// Convert the text from string to byte array for decryption 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       var encryptedBytes = byteConverter.GetBytes(message); 

       //// Create an aux array to store all the encrypted bytes 
       byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false); 

       decryptedText = byteConverter.GetString(decryptedBytes); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return decryptedText; 
    } 

我知道,這是文字的牆,但我希望你能幫助我,因爲我一直在敲打我的頭撞牆了這麼久,現在它是不好笑:)

問題是,我怎麼去加密消息與RSA(或任何其他公共/私人密鑰加密)

下面是測試客戶端:

public static void Main(string[] args) 
    { 
     PublicKeyInfrastructure pki = new PublicKeyInfrastructure(); 
     Cryptograph crypto = new Cryptograph(); 
     string[] keys = crypto.GenerateKeysToStrings("[email protected]"); 


     string plainText = "Hello play with me, please"; 
     string publicKey = crypto.GetPublicKey("[email protected]"); 

     string encryptedText = crypto.Encrypt(keys[0], plainText); 


     string decryptedText = crypto.Decrypt(keys[1], encryptedText); 

    } 

正如我提到的,字符串數組有沒有因爲我想消除來自XML文檔的錯誤解析錯誤...

當我運行測試客戶端時,如果我使用私鑰進行加密和公鑰解密,我得到一個「密鑰不存在異常」和如果我這樣做,我會得到一個不好的數據異常。

請幫幫我,如果你知道任何好的指導,或者可以告訴我如何在字符串消息上實現公鑰/私鑰加密,請幫助我。

我很感激任何幫助。

回答

5

這不是RSA加密應該如何完成的。

RSA是關於數學的。你加密的是一個數字,因此它必須是有限長度的,並且與你使用的RSA密鑰對長度相匹配。進一步的長度限制是由使用的填充(PKCS#1或OAEP)施加的。

如果要使用RSA對大數據進行加密,則需要間接完成 - 即使用對稱密鑰來加密大數據並使用RSA公鑰對此密鑰進行加密。

你可以閱讀關於在我的blog上執行此操作的信息。

+0

我和我的教授交談過,當時我的觀點是,加密密鑰,交換密鑰和然後用它作爲對稱算法的基礎,就像rijndael來加密/解密信息一樣,但是,他不希望我們使用對稱加密,所以現在我處於一個不受限制的位置。性能方面,當我們談論包含用戶名和密碼的HTTP消息時,需要多少時間來加密消息,每次501字節(使用4096位RSA密鑰)?編碼塊或不是,我仍然有實際使用RSA的問題:( –

+0

)您可以循環RSA加密/解密以保持大小限制(包括填充)並連接/拆分結果。多長時間?取決於你的CPU,它是一箇舊的智能手機和一個新的8核心服務器?;-),但比正確的選擇更長。 – poupou

+0

我希望我能夠做到這一點,但現在我甚至無法獲得任何數據。我使用了一個簡化版本,然而,我仍然得到「Key does not exist」的錯誤,而我所做的只是重構設計,從單一的主要方法到單獨的方法。 也許我正在使用構造函數嗎?我輸入密鑰設置的部分?我知道塊密碼比對稱算法慢1000倍,但現在我只是希望它能夠工作,無論我是否必須對其進行硬編碼,以便將每塊數據分塊(keyize/8 - 11(用於填充))字節。 –

0

也許我錯過了一些東西,但它看起來像您的加密()函數不使用keyString參數或encryptKey的內容。

+0

是的,我很遺憾,但我一定忘了把它放在那裏,但我向你保證我已經確保加載密鑰。我現在更新了OP。我剛剛嘗試加載數據很多次,我必須得到一些混合的版本,並沒有看到它:)我的問題仍然存在,但。 現在我遇到的問題是,當我使用我的私鑰進行加密並且公衆解密時,我得到一個keyDoesn'tExist異常。如果我以其他方式執行此操作,則會收到「不良數據」異常。 –

1

好吧,我終於想出了一個解決方案,我在我原來的帖子中說過的問題。這是我沒有經過徹底測試或者什麼的,但是我從一個小小的試驗和錯誤過程中發現了一些東西。

下面是當前代碼我有:

public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo) 
    { 
     //// Our bytearray to hold all of our data after the encryption 
     byte[] encryptedBytes = new byte[0]; 
     using (var RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //Create a new instance of RSACryptoServiceProvider. 
       UTF8Encoding encoder = new UTF8Encoding(); 

       byte[] encryptThis = encoder.GetBytes(dataToEncrypt); 

       //// Importing the public key 
       RSA.ImportParameters(publicKeyInfo); 

       int blockSize = (RSA.KeySize/8) - 32; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       byte[] encryptedBuffer = new byte[blockSize]; 

       //// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted 
       encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32]; 

       for (int i = 0; i < encryptThis.Length; i += blockSize) 
       { 
        //// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data 
        if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[encryptThis.Length - i]; 
         blockSize = encryptThis.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (encryptThis.Length < blockSize) 
        { 
         buffer = new byte[encryptThis.Length]; 
         blockSize = encryptThis.Length; 
        } 

        //// encrypt the specified size of data, then add to final array. 
        Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize); 
        encryptedBuffer = RSA.Encrypt(buffer, false); 
        encryptedBuffer.CopyTo(encryptedBytes, i); 
       } 
      } 
      catch (CryptographicException e) 
      { 
       Console.Write(e); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 
     //// Convert the byteArray using Base64 and returns as an encrypted string 
     return Convert.ToBase64String(encryptedBytes); 
    } 

    /// <summary> 
    /// Decrypt this message using this key 
    /// </summary> 
    /// <param name="dataToDecrypt"> 
    /// The data To decrypt. 
    /// </param> 
    /// <param name="privateKeyInfo"> 
    /// The private Key Info. 
    /// </param> 
    /// <returns> 
    /// The decrypted data. 
    /// </returns> 
    public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo) 
    { 
     //// The bytearray to hold all of our data after decryption 
     byte[] decryptedBytes; 

     //Create a new instance of RSACryptoServiceProvider. 
     using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt); 

       //// Import the private key info 
       RSA.ImportParameters(privateKeyInfo); 

       //// No need to subtract padding size when decrypting (OR do I?) 
       int blockSize = RSA.KeySize/8; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       //// buffer containing decrypted information 
       byte[] decryptedBuffer = new byte[blockSize]; 

       //// Initializes our array to make sure it can hold at least the amount needed to decrypt. 
       decryptedBytes = new byte[dataToDecrypt.Length]; 

       for (int i = 0; i < bytesToDecrypt.Length; i += blockSize) 
       { 
        if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[bytesToDecrypt.Length - i]; 
         blockSize = bytesToDecrypt.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (bytesToDecrypt.Length < blockSize) 
        { 
         buffer = new byte[bytesToDecrypt.Length]; 
         blockSize = bytesToDecrypt.Length; 
        } 

        Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize); 
        decryptedBuffer = RSA.Decrypt(buffer, false); 
        decryptedBuffer.CopyTo(decryptedBytes, i); 
       } 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 

     //// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead. 
     var encoder = new UTF8Encoding(); 
     return encoder.GetString(decryptedBytes).TrimEnd(new[] { '\0' }); 

    } 

正如我所說的,我沒有測試過了,除了以下尺寸,在以上的塊大小等,但它似乎是在做什麼這應該。我仍然是一個新手,所以我真的很想你審查我的代碼:)