Encrypt AesCryptoServiceProvider return zero byte array?

断了今生、忘了曾经 提交于 2019-12-11 05:13:37

问题


I encounter an error when using the AesCryptoServiceProvider to Encrypt some files config. The summary code is below

private static byte[] secretKey =     {
                                                        (byte)0x63, (byte)0x23, (byte)0xdf, (byte)0x2a,
                                                        (byte)0x59, (byte)0x1a, (byte)0xac, (byte)0xcc,
                                                        (byte)0x50, (byte)0xfa, (byte)0x0d, (byte)0xcc,
                                                        (byte)0xff, (byte)0xfd, (byte)0xda, (byte)0xf0                                           
                                                    };                          

private static byte[] iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

public static byte[] EncryptStringToBytes(String plainText, byte[] secretKey, byte[] IV)
{
    try
    {
        // Check arguments. 
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (secretKey == null || secretKey.Length <= 0)
            throw new ArgumentNullException("secretKey");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("secretKey");

        byte[] encrypted;

        // Create an AesCryptoServiceProvider object 
        // with the specified key and IV. 
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.Key = secretKey;
            aesAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption. 
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        return encrypted;
    }
    catch (System.Exception ex)
    {
        LogWriter.Instance.LogError(ClassName, "EncryptStringToBytes()", ex.Message + ";\tplainText=" + plainText + ";\t" + ex.StackTrace);
        return null;
    }
}

int main()
{
    byte[] encryptText = EncryptStringToBytes("some plain text", secretKey, iv);
    if (encryptText != null)
    {
        try
        {
            File.WriteAllBytes(filePath, encryptText);
        }
        catch (Exception ex)
        {
            LogWriter.Instance.LogError(ClassName, "SaveBuffToFile()", ex.Message + ";\tFilePath=" + path + ";\t" + ex.StackTrace);
        }
    }
}

In the main function, I Encrypt the plain text and save the result to the file by calling File.WriteAllBytes(filePath, encryptText);. But sometime the content file contains all Null character ('\0'). The bellow image is the content of file when I open with HexaEditor

This error happen about once a month for the app running 8 hours per day.

I considered that the file may be corrupted. But I think that this case is not caused by corruption, because there are 10 config files in a folder, but only have 7 files that using Encryption is encountered this error, whereas 3 files that saved by plain text (not using Encryption) has never encountered this error.

So I think the problem caused by AesCryptoServiceProvider. Anyone please help me.

Thank you!


回答1:


NOTE: Thanks to Damien_The_Unbeliever and his testing, this answer has been found to be WRONG and may be deleted soon. Until then, it should help others avoid going down this path.


You may have a race condition with the ToArray() call on your MemoryStream.

The code you posted calls that method outside of the using statement for StreamWriter, so that object will have flushed any buffers it may be using to the underlying CryptoStream by that point, but the call is inside the using statement for CryptoStream, which means there is no guarantee that that object will have flushed any buffers to the underlying MemoryStream by that point.

That would explain the intermittent nature of the bug:

In the cases where you get the desired result, it might be that the CryptoStream's buffer is being automatically flushed to the MemoryStream before the call to ToArray(), just by luck.

In the cases where you're getting the erroneous result, the ToArray() call is returning the data from the MemoryStream's internal buffer (which is most likely being initialized to zeros) before the MemoryStream has received all (or any) of the data from the CryptoStream.

If that is all correct, you can make the buffer flushing deterministic and guarantee a correct result every time by calling FlushFinalBlock() on the CryptoStream object before accessing the data from its underlying MemoryStream.

After that change, the code would be:

[...]

// Create the streams used for encryption. 
using ( MemoryStream msEncrypt = new MemoryStream() ) {

    using ( CryptoStream csEncrypt = new CryptoStream( msEncrypt, encryptor, CryptoStreamMode.Write ) ) {

        using ( StreamWriter swEncrypt = new StreamWriter( csEncrypt ) ) {

            swEncrypt.Write( plainText );

        }

        csEncrypt.FlushFinalBlock();
        encrypted = msEncrypt.ToArray();

    }

}

[...]

See:

CryptoStream.HasFlushedFinalBlock

This StackOverflow answer is tangentially related to your issue: https://stackoverflow.com/a/19742806



来源:https://stackoverflow.com/questions/49269579/encrypt-aescryptoserviceprovider-return-zero-byte-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!