解密异常 - 要解密的数据长度无效

时间:2014-03-17 22:35:45

标签: c# encryption cryptography rijndael

我在C#应用程序中工作。我们有将数据存储在文件中的常用方法。这些方法加密数据并将其存储在文件系统上。当我们需要数据时,ReadData方法解密数据并返回纯文本。

如果文本的大小很小,这段代码在正常情况下工作正常。但是对于下面给出的示例文本,解密代码抛出异常 - 要解密的数据长度无效。

异常发生在

        // close the CryptoStream
        x_cryptostream.Close();

我尝试了不同的方法,但没有运气。有些人可以帮忙。

为什么我要加密已经加密的数据 - 我只是试图使用庞大应用程序的常用方法存储在文件中。常见方法storedata(key,data) nad readdata(key)执行我无法避免的加密/解密。

   public static byte[] Decrypt(byte[] ciphertext, string Key, string IV)
    {
        byte[] k = Encoding.Default.GetBytes(Key);
        byte[] iv = Encoding.Default.GetBytes(IV);

        // create the encryption algorithm
        SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
        x_alg.Padding = PaddingMode.PKCS7;

        // create an ICryptoTransform that can be used to decrypt data
        ICryptoTransform x_decryptor = x_alg.CreateDecryptor(k, iv);

        // create the memory stream
        MemoryStream x_memory_stream = new MemoryStream();

        // create the CryptoStream that ties together the MemoryStream and the 
        // ICryptostream
        CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
        x_decryptor, CryptoStreamMode.Write);

        // write the ciphertext out to the cryptostream
        x_cryptostream.Write(ciphertext, 0, ciphertext.Length);

        // close the CryptoStream
        x_cryptostream.Close();

        // get the plaintext from the MemoryStream
        byte[] x_plaintext = x_memory_stream.ToArray();

以下是加密方法的代码。

        public static byte[] Encrypt(string strplain, string Key, string IV)
        {
        byte[] k = Encoding.Default.GetBytes(Key);
        byte[] iv = Encoding.Default.GetBytes(IV);

        byte[] plaintext = Encoding.Default.GetBytes(strplain);

        // create the encryption algorithm
        SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
        x_alg.Padding = PaddingMode.PKCS7;
        // create an ICryptoTransform that can be used to encrypt data
        ICryptoTransform x_encryptor = x_alg.CreateEncryptor(k, iv);

        // create the memory stream
        MemoryStream x_memory_stream = new MemoryStream();

        // create the CryptoStream that ties together the MemoryStream and
        // the ICryptostream
        CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
        x_encryptor, CryptoStreamMode.Write);

        // write the plaintext out to the cryptostream
        x_cryptostream.Write(plaintext, 0, plaintext.Length);

        // close the CryptoStream
        x_cryptostream.Close();

        // get the ciphertext from the MemoryStream
        byte[] x_ciphertext = x_memory_stream.ToArray();

        // close memory stream
        x_memory_stream.Close();

        // convert from array to string
        string cipher_Tx = Encoding.Default.GetString(x_ciphertext, 
            0, x_ciphertext.Length);

        x_encryptor.Dispose();

        x_alg.Clear();
        byte[] cipher = Encoding.Default.GetBytes(cipher_Tx);

        return cipher;
    }  

2 个答案:

答案 0 :(得分:9)

您的问题是string cipher_Tx = Encoding.Default.GetString(x_ciphertext, 0, x_ciphertext.Length);

x_ciphertext不是文本的有效字节表示形式,它有许多不可发现的字符,当您执行byte[]string转换时,您将丢失信息。正确的方法是使用一种字符串格式,用于表示使用Convert.ToBase64String(byte[])Convert.FromBase64String(string)之类的二进制数据。

string cipher_Tx = Convert.ToBase64String(x_ciphertext)

x_encryptor.Dispose();

x_alg.Clear();
byte[] cipher = Convert.FromBase64String(cipher_Tx)

话虽这么说,你的代码还有很多其他“奇怪”的东西,例如你不使用using语句,你真的应该这样做。此外,完全转换为字符串和返回是完全没必要的,只需返回x_ciphertext。代码可能还有其他问题(比如KeyIV的字符串来自哪里)和许多其他最佳实践(比如你应该生成一个随机的IV并将其写入输出和密钥应该使用密钥派生函数生成,而不是直接来自用户文本),但是在找到字符串转换问题后我停止了检查。

答案 1 :(得分:0)

只要用于解密的密钥和iv与用于加密的iv匹配,上面的代码就可以正常工作。试试这个:

byte[] test = new byte[1000000];
for (int i = 0; i < 256; i++)
{
    test[i] = (byte)i;
}
var ciphertext = Encrypt(Encoding.Default.GetString(test), "0000000000000000", "0000000000000000");
byte[] check = Decrypt(ciphertext, "0000000000000000", "0000000000000000");
for (int i = 0; i < 256; i++)
{
    Debug.Assert(check[i] == (byte)i, "round trip");
}

正如您所看到的,一百万字节可以使用您的代码加密和解密,所以我认为它与数据大小无关。

然而,像这样改变IV:

byte[] check = Decrypt(ciphertext, "0000000000000000", "000000000000000X"); // note X

并且Debug.Assert将触发 - 解密将不匹配。但是,x_cryptostream.Close()成功。

接下来,尝试更改此键:

byte[] check = Decrypt(ciphertext, "000000000000000X", "0000000000000000"); // note X

现在,x_cryptostream.Close()将因CryptographicException而失败,可能是“Padding无效且无法删除。”

破坏密钥会导致解密失败,x_cryptostream.Close()失败。

我认为问题在于您的保存以及稍后恢复关键字节。

BTW:希望你使用密钥的完整二进制范围,而不仅仅是基于ASCII字符,否则你真的没有强密钥。

相关问题