C#AES加密只执行一次

时间:2014-08-04 20:48:39

标签: c# winforms cryptography

我有一个C#WinForms应用程序,带有AES加密/解密功能。加密(解密)本身工作正常,但只有一次。如果我尝试加密另一个字符串,我会收到一个CryptographyException,说填充是无效的。基于一些研究,似乎我忘了关闭一些流,但我无法弄清楚它是什么。有谁知道如何解决这一问题? 这是我使用的代码(我相信我之前发现它的某些内容):

    static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key
, byte[] IV)
    {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        // Create an Aes object
        // with the specified key and IV.
        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Key = Key;
            aesAlg.IV = IV;

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

            // Create the streams used for decryption.
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt
, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(
csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                        //csDecrypt.FlushFinalBlock(); causes an exception
                            plaintext = srDecrypt.ReadToEnd();
                            //csDecrypt.Flush(); experimental solution, doesn't work           either
                            srDecrypt.Close();
                    }
                    csDecrypt.Close();

                }
                msDecrypt.Close();
            }        

        }

        return plaintext;

    }

    static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,
byte[] IV)
    {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");
        byte[] encrypted;
        // Create an Aes object
        // with the specified key and IV.
        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Key = Key;
            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))
                    {

                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                        swEncrypt.Close();
                    }
                    csEncrypt.Close();
                    msEncrypt.Close();
                    encrypted = msEncrypt.ToArray();

                    //csEncrypt.FlushFinalBlock(); causes an exception saying it was already called
                }

            }
        }

以下是我用来测试ecnryption的代码示例。正确执行,但只执行一次...... 密钥和IV被转换为Unicode字符串,以便用户能够保存它并在以后用于解密。

        private void button7_Click(object sender, EventArgs e)
    {
        string aesKey = "";
        string aesIV = "";
        string ciphered = "";
        string deciphered = "";
        using (Aes myAes = Aes.Create())
        {
            myAes.GenerateKey();
            myAes.GenerateIV();
            aesKey = Encoding.Unicode.GetString(myAes.Key);
            aesIV = Encoding.Unicode.GetString(myAes.IV);

            ciphered = Encoding.Unicode.GetString(EncryptStringToBytes_Aes(".ahoj.",    myAes.Key, myAes.IV));

            byte[] deKey = Encoding.Unicode.GetBytes(aesKey);
            byte[] deIv = Encoding.Unicode.GetBytes(aesIV);

            deciphered =    DecryptStringFromBytes_Aes(Encoding.Unicode.GetBytes(ciphered), deKey, deIv);

            MessageBox.Show("key: " + aesKey + "\niv: " + aesIV + "\ndekey: " + Encoding.Unicode.GetString(deKey) + "\ndeIv: " + Encoding.Unicode.GetString(deIv) + "\nDeciphered: " + deciphered);

        }
    }

2 个答案:

答案 0 :(得分:0)

我建议使用base 64编码字节,而不是使用unicode编码中的GetBytesGetString

您可以使用Convert.ToBase64String()Convert.FromBase64String进行base 64编码。

从生成的字节数组中获取unicode字符串的一个问题是无法保证所有字符都是可打印字符。例如,如果字节数组中有0,那么它将是一个空控制字符。

答案 1 :(得分:0)

我最近遇到了这个问题。我正在使用&#39;使用&#39;您的第一个代码块中的语句,但我从不致电.Close(),我没有遇到只能运行一次的问题。

要解决在解密和发布不可打印字符时填充的问题,我明确设置Padding,就像您在第一个代码块中所做的那样,但我使用Encoding.Default.GetBytes(cipherText);和{{1相同编码的方法,因此它使用Window的默认扩展ASCII编码,因此它将识别所有字符。