2014-02-22 70 views
2

我目前得到一個文件夾完整的1280x720 AES加密位圖。C# - AES解密性能慢

我試圖通過文件夾來創建一個播放器環路解密圖像,並在圖像框顯示他們(以合理的速度)

重要的是我不想要的文件進行解密,以驅動然後播放。我只想在內存中解密它們。

目前解密每個圖像(幀)需要大約100ms。但如果可能的話,我想嘗試將其降低到大約10ms。

以上是異形的iCore7

目前我正在運行UI線程上一切3.0GHz的。我想也許如果我多線程解密,我可能會得到我想要的速度,那麼我將不得不在內存中存儲很多。但我寧願看看我能否更快地實際解密。

這裏是解密函數:

private byte[] DecryptFile(string inputFile, string skey) 
{ 

MemoryStream output1 = new MemoryStream(); 

// ok for tests.. 
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(skey, new byte[] { 10, 10, 10, 10, 10, 10, 10, 10 }); 

try 
{ 
    using (RijndaelManaged aes = new RijndaelManaged()) 
    { 
     byte[] key = k2.GetBytes(16); 

     /* This is for demostrating purposes only. 
     * Ideally yu will want the IV key to be different from your key and you should always generate a new one for each encryption in other to achieve maximum security*/ 
     byte[] IV = k2.GetBytes(16); 

     byte[] cript = File.ReadAllBytes(inputFile); 


     using (MemoryStream fsCrypt = new MemoryStream(cript)) 
     { 

       using (ICryptoTransform decryptor = aes.CreateDecryptor(key, IV)) 
       { 
        using (CryptoStream cs = new CryptoStream(fsCrypt, decryptor, CryptoStreamMode.Read)) 
        { 
         cs.CopyTo(output1); 
        } 
      } 
     } 
    } 
} 
catch (Exception ex) 
{ 
    MessageBox.Show(ex.Message); 
} 

return output1.ToArray() ; 
} 

難道還有比上面的函數來解密更有效的方法?

+0

看來你創建了很多東西,每通過循環。也許如果你能「把它弄出來」,你不會花太多時間來初始化。你是否簡介了代碼 - 你知道你大部分時間在哪裏?顯然,如果你有一個i7,你需要以多線程的方式寫這個 - 至少保持所有這些處理器忙碌,如果你可以...... – Floris

+0

大約98%的時間被cs.CopyTo(output1)行佔用。 即使我把它縮小到10ms,我也會把它寫成多線程的,但是現在我想盡可能快地得到這個函數:) – james

回答

7

您可以使用更快的AesCryptoServiceProvider

RijndaelManaged這是一個純粹的託管實現對比,AesCryptoServiceProvider使用Windows Crypto API。

+0

這個時間減半了!下降到50ms!不知道是否有辦法擠出更多一點 – james

+0

@james如果鍵都一樣不要使用'Rfc2898DeriveBytes'每個文件。獲取byte []一次並重新使用它。以我的答案爲例。 –

+0

@ScottChamberlain我現在只是在嘗試。雖然我得到了一個「填充問題」,這是非常奇怪的。因爲我所做的一切都是拉解密以外的關鍵,只是傳遞關鍵字節....應該是完全一樣的! – james

0

如果您想「推出自己的產品」,您可能需要查看this paper,其中描述了適合最佳AES性能的i7新指令。如果你的C#庫沒有利用那些你可能會獲得很好的速度提升。

從這篇文章看來,您希望用256字節密鑰實現的最佳效果大約爲0.32個周/字節 - 對於使用超線程的所有內核的1MB文件和3 GHz處理器,大致爲0.1 ms每個文件。這比你所看到的要快1000倍 - 所以是的,你似乎已經遠遠超過了「最高速度」標記。同樣的文章聲稱單核的速度要慢6倍 - 仍然比你看到的要快。

雖然我會在寫自己的作品之前去尋找其他的圖書館。看看英特爾提供的那個:http://software.intel.com/en-us/articles/download-the-intel-aesni-sample-library

0

這是我在我的系統中使用的...不知道它是否會更快。這似乎只是你正在做的閱讀和複製了沒有必要的量:​​

Public Shared Function ReadImageAES(ByVal FileName As String) As Image 
    Dim img As Image = Nothing 
    Try 
     Using fs As New FileStream(FileName, FileMode.Open) 
      Using cs As New CryptoStream(fs, Crypto.AES.CreateDecryptor, CryptoStreamMode.Read) 
       img = Image.FromStream(cs) 
      End Using 
     End Using 
    Catch ex As Exception 
     img = Nothing 
     'Debug.Print("ReadImageAES()failed: " & ex.ToString) 
    End Try 
    Return img 
End Function 

Public Shared Sub WriteImageAES(ByVal FileName As String, ByVal img As Image, Optional ByVal NewUserKey As String = Nothing) 
    If Not IsNothing(img) Then 
     Try 
      If File.Exists(FileName) Then 
       File.Delete(FileName) 
      End If 
      Using fs As New FileStream(FileName, FileMode.OpenOrCreate) 
       Dim Key() As Byte 
       If IsNothing(NewUserKey) Then 
        Key = Crypto.AES.Key 
       Else 
        Key = Crypto.SHA256Hash(NewUserKey) 
       End If 
       Using cs As New CryptoStream(fs, Crypto.AES.CreateEncryptor(Key, Crypto.AES.IV), CryptoStreamMode.Write) 
        Dim bmp As New Bitmap(img) 
        bmp.Save(cs, System.Drawing.Imaging.ImageFormat.Jpeg) 
        bmp.Dispose() 
        cs.FlushFinalBlock() 
       End Using 
      End Using 
     Catch ex As Exception 
      'Debug.Print("WriteImageAES() Failed: " & ex.ToString) 
     End Try 
    Else 
     MessageBox.Show(FileName, "GetImage() Failed") 
    End If 
End Sub 

這裏是我的加密類,原本是寫僅面向.NET 2.0:

Imports System.IO 
Imports System.Text 
Imports System.Security.Cryptography 
Public Class Crypto 

    Private Shared _UserKey As String = "" 
    Private Shared _SHA256 As New SHA256Managed 
    Private Shared _AES As New RijndaelManaged 
    Private Const _IV As String = "P5acZMXujMRdmYvFXYfncS7XhrsPNfHkerTnWVT6JcfcfHFDwa" ' <--- this can be anything you want 

    Public Shared Property UserKey() As String 
     Get 
      Return Crypto._UserKey 
     End Get 
     Set(ByVal value As String) 
      Crypto._UserKey = value 
      Crypto._AES.KeySize = 256 
      Crypto._AES.BlockSize = 256 
      Crypto._AES.Key = Crypto.SHA256Hash(Crypto._UserKey) 
      Crypto._AES.IV = Crypto.SHA256Hash(Crypto._IV) 
      Crypto._AES.Mode = CipherMode.CBC 
     End Set 
    End Property 

    Public Shared Function SHA256Hash(ByVal value As String) As Byte() 
     Return Crypto._SHA256.ComputeHash(ASCIIEncoding.ASCII.GetBytes(value)) 
    End Function 

    Public Shared ReadOnly Property AES() As RijndaelManaged 
     Get 
      Return Crypto._AES 
     End Get 
    End Property 

End Class 
3

Rfc2898DeriveBytes是設計爲故意緩慢,它用來減緩暴力破解企圖。由於每個文件看起來像使用相同的密鑰和IV(順便說一句,爲了解決在註釋中說的IV問題,只需將IV的第一個字節存儲在文件本身中即可,IV不需要保密,只有鑰匙)

這是一個更新版本,還有一些其他的調整。

private IEnumerable<byte[]> DecryptFiles(IEnumerable<string> inputFiles, string skey) 
{ 
    //Only performing the key calculation once. 
    Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(skey, new byte[] { 10, 10, 10, 10, 10, 10, 10, 10 }); 
    byte[] key = k2.GetBytes(16) 

    foreach(var inputFile in inputFiles) 
    { 
     yield return DecryptFile(inputFile, key); 
    } 
} 

private byte[] DecryptFile(string inputFile, byte[] key) 
{ 
    var output1 = new MemoryStream(); 

    try 
    { 
     //If you are going to use AES, then use AES, also the CSP is faster than the managed version. 
     using (var aes = new AesCryptoServiceProvider()) 
     { 
      //No need to copy the file in to memory first, just read it from the hard drive. 
      using(var fsCrypt = File.OpenRead(inputFile)) 
      { 
       //Gets the IV from the header of the file, you will need to modify your Encrypt process to write it. 
       byte[] IV = GetIV(fsCrypt); 

       //You can chain consecutive using statements like this without brackets. 
       using (var decryptor = aes.CreateDecryptor(key, IV)) 
       using (var cs = new CryptoStream(fsCrypt, decryptor, CryptoStreamMode.Read)) 
       { 
        cs.CopyTo(output1); 
       } 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
    } 

    return output1.ToArray(); 
} 

//This function assumes you wrote a 32 bit length then the array that was the read length long. 
private static byte[] GetIV(Stream fileStream) 
{ 
    var reader = new BinaryReader(fileStream); 
    var keyLength = reader.ReadInt32(); 
    return reader.ReadBytes(keyLength); 
} 
+0

這確實給了我速度提高了8-9毫秒。 – james

+0

@james當你正在測試時,你是否正在使用附帶的調試器測試它在Visual Studio中運行?嘗試在發佈模式下編譯它,只需在沒有任何調試器的情況下在Visual Studio之外打開exe文件,然後查看您獲得的時間差異。 –

+0

我在前幾個小時確實犯了這個錯誤。在沒有附加調試器的情況下,注意版本版本速度提高10%左右 – james

0

將字節數組嚴格用作輸出而不是您的MemoryStream時,速度幾乎快了兩倍。

我的代碼示例:

byte[] ds = new byte[data.Length]; 
byte[] decryptedData; 
using (Aes aes = CreateAes(key, iv, cipherMode, paddingMode)) 
{ 
    using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV)) 
    { 
     int i = 0; 
     using (MemoryStream msDecrypt = new MemoryStream(data)) 
     { 
      using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) 
      { 
       int k; 
       while ((k = csDecrypt.ReadByte()) != -1) 
       { 
        ds[i++] = (byte)k; 
       } 
      } 
     } 
     decryptedData = new byte[i]; 
     Buffer.BlockCopy(ds, 0, decryptedData, 0, i); 
    } 
} 
return decryptedData;