C# Rijndael 解密不适用于 jpgs

C# Rijndael Decryption doesn't work with jpgs

当我尝试加密和解密一个简单的字符串时,一切都非常顺利..

但是当我将一个 jpg 编码成一个字节数组并对该字节数组执行完全相同的操作时,解密不再起作用(字节数组与原始字节数组完全不同,无法再显示)...

是不是字节数组太大了?

或者有人能解决我的问题吗?

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Encrypter2
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {

                Console.WriteLine();
                // Create a new instance of the Rijndael
                // class.  This generates a new key and initialization 
                // vector (IV).
                byte[] originalFile = File.ReadAllBytes(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambe.jpg");
                using (Rijndael myRijndael = Rijndael.Create())
                {
                //     Encrypt the string to an array of bytes
                //    Encrypted byte[]
                byte[] encrypted = EncryptStringToBytes(originalFile, myRijndael.Key, myRijndael.IV);
                    using (FileStream fs = File.Create(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambeEncrypted.jpg"))
                    {
                        //Add some information to the file.
                        fs.Write(encrypted, 0, encrypted.Length);
                    }
                //     Decrypted byte[]
                byte[] roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);
                    using (FileStream fs = File.Create(@"C:/Users/Elron/Documents/Visual Studio 2015/Projects/FileEncrypt/FileEncrypt/bin/Debug/harambeDecrypted.jpg"))
                    {
                        //Add some information to the file.
                        fs.Write(roundtrip, 0, roundtrip.Length);
                    }
                //    Display the original data and the decrypted data.
                //    Encrypted string
                    Console.ReadKey();
            }

            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
        }

        static byte[] EncryptStringToBytes(byte[] 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("IV");
            byte[] encrypted;
            // Create an Rijndael object
            // with the specified key and IV.
            using (Rijndael rijAlg = Rijndael.Create())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.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.
                            string toEncrypt = Encoding.Default.GetString(plainText);
                            swEncrypt.Write(toEncrypt);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream.
            return encrypted;

        }

        static byte[] DecryptStringFromBytes(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("IV");

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;
            byte[] returnText;

            // Create an Rijndael object
            // with the specified key and IV.
            using (Rijndael rijAlg = Rijndael.Create())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decryptor to perform the stream transform.
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.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.
                            plaintext = srDecrypt.ReadToEnd();


                            ASCIIEncoding asc = new ASCIIEncoding();
                            returnText = asc.GetBytes(plaintext);
                        }
                    }
                }
            }
            return returnText;
        }
    }
}

我认为您在加密和解密方法中使用了不同的编码

static byte[] DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
    ...
    ASCIIEncoding asc = new ASCIIEncoding();
    returnText = asc.GetBytes(plaintext);
    ...
}

   static byte[] EncryptStringToBytes(byte[] plainText, byte[] Key, byte[] IV)
    {
        ...
        string toEncrypt = Encoding.Default.GetString(plainText);
        swEncrypt.Write(toEncrypt);
        ...
    }

您不能将任意字节数组视为字符串。您获取字节,将它们转换为字符串,然后将字符串写入 StreamWriter,后者将字符串转换回字节。这将是对一堆任意字节的有损操作。

您的方法EncryptStringToBytes是一个错误的概念。您应该有一个不关心字符串的方法 EncryptBytes(和 DecryptBytes)。然后你可以传入一个字节数组并将其直接输入到 CryptoStream 中。如何解释这些字节不是加密算法的关注点。

所以你可以调整你的方法如下:

static byte[] EncryptBytes(byte[] bytes, byte[] Key, byte[] IV)
{
    // Check arguments.
    if (bytes == null || bytes.Length <= 0)
        throw new ArgumentNullException("bytes");
    if (Key == null || Key.Length <= 0)
        throw new ArgumentNullException("Key");
    if (IV == null || IV.Length <= 0)
        throw new ArgumentNullException("IV");
    // Create an Rijndael object
    // with the specified key and IV.
    using (Rijndael rijAlg = Rijndael.Create())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;

        // Create an encryptor to perform the stream transform.
        ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

        // Create the streams used for encryption.
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, 
                    CryptoStreamMode.Write))
            {
                csEncrypt.Write(bytes,0,bytes.Length);
                csEncrypt.FlushFinalBlock();
                return msEncrypt.ToArray();
            }
        }
    }
}

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

    // Create an Rijndael object
    // with the specified key and IV.
    using (Rijndael rijAlg = Rijndael.Create())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;

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

        // Create the streams used for decryption.
        using (MemoryStream msDecrypt = new MemoryStream())
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, 
                    CryptoStreamMode.Write))
            {
                csDecrypt.Write(encryptedBytes,0,encryptedBytes.Length);
                csDecrypt.FlushFinalBlock();
                return msDecrypt.ToArray();
            }
        }
    }

}

然后进行往返测试:

using(var rijndael = Rijndael.Create())
{
    var stringToEncrypt = "foobar";
    var bytesToEncrypt = Encoding.UTF8.GetBytes(stringToEncrypt);
    var encryptedBytes = EncryptBytes(bytesToEncrypt, rijndael.Key, rijndael.IV);
    var decryptedBytes = DecryptBytes(encryptedBytes, rijndael.Key, rijndael.IV);
    var originalString = Encoding.UTF8.GetString(decryptedBytes);
    Debug.Assert(string.Equals(stringToEncrypt, originalString, 
                                StringComparison.InvariantCulture));
}

希望到此为止,我们已经清楚地了解了我们如何从加密中分离出字符串编码问题,以及您现在可以如何将这些方法重新用于任何类型的二进制数据。