C# - AES解密性能缓慢

时间:2014-02-22 19:40:36

标签: c# encryption aes

我目前有一个装满1280x720 AES加密位图的文件夹。

我正在尝试创建一个循环播放文件夹的播放器解密图像并在图像框中显示(以合理的速度)

重要的是,我不希望将文件解密到驱动器然后播放。我想只在内存中解密它们。

目前,每张图像(帧)的解密时间约为100毫秒。但是如果可能的话,我想尝试将其降低到大约10毫秒。

以上是在3.0ghz iCore7上进行了描述

目前我在UI线程上运行所有内容。我想也许如果我多线程解密我可能得到我想要的速度,那么我将不得不在内存中存储很多。但我宁愿看看我是否可以更快地进行实际的解密。

这是解密功能:

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() ;
}

是否有比上述功能更有效的解密方法?

5 个答案:

答案 0 :(得分:8)

您可以使用速度更快的AesCryptoServiceProvider

RijndaelManaged纯粹的托管实现相比,AesCryptoServiceProvider使用Windows Crypto API。

答案 1 :(得分:5)

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);
}

答案 2 :(得分:0)

如果您想“自己动手”,可能需要查看this paper,其中介绍i7上针对最佳AES性能的新指令。如果你的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

答案 3 :(得分: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

这是我的Crypto类,最初只编写目标.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

答案 4 :(得分: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;