奇怪的加密/解密错误 (C# - AES)

本文关键字:AES 错误 解密 加密 | 更新日期: 2023-09-27 17:56:22

我从这里的另一个问题中找到了以下AES加密类。该类(按原样)效果很好,但是,我一直在尝试根据自己的喜好修改该类,这就是我遇到这些错误的地方。请注意,这是我尝试加密的二进制文件。

首先,我将解释我正在尝试进行的更改。

1)我想将加密函数的参数从字符串更改为字节数组。我认为这将是非常简单的任务(只需快速执行File.ReadAllBytes并将字节数组传递给Encrypt函数),但事实并非如此。

2)我希望解密函数返回一个字节数组。与上述相同的问题,我无法使其正常工作。

我希望有人能够给我一个加密和解密二进制文件的工作示例,类似于我在下面设置的:

private void button1_Click(object sender, EventArgs e)
    {
        SimpleAES sa = new SimpleAES();
        OpenFileDialog ofd = new OpenFileDialog();
        string s = string.Empty;
        byte[] b = null;
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            textBox1.Text = ofd.FileName;
            b = File.ReadAllBytes(ofd.FileName);
            b = sa.Encrypt(ByteToString(b);
        }
        File.WriteAllBytes(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"'TestData123.exe", b);
    }
    private void button2_Click(object sender, EventArgs e)
    {
        SimpleAES sa = new SimpleAES();
        byte[] b = File.ReadAllBytes(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"'TestData123.exe");
        string s = sa.Decrypt(b);
        File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"'TestData123.exe");
        File.WriteAllBytes(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"'TestData.exe", b);
    }
    public byte[] StringToByte(string s)
    {
        Byte[] b = new byte[s.Length];
        for (int i = 0; i < s.Length; i++)
        {
            char c = Convert.ToChar(s.Substring(i, 1));
            b[i] = Convert.ToByte(c);
        }
        return b;
    }
    public string ByteToString(byte[] input)
    {
        StringBuilder ss = new System.Text.StringBuilder();
        for (int i = 0; i < input.Length; i++)
        {
            // Convert each byte to char
            char c = Convert.ToChar(input[i]);
            ss.Append(Convert.ToString(c));
        }
        return ss.ToString();
    }

这是我正在使用的 AES 类:

using System;
using System.Data;
using System.Security.Cryptography;
using System.IO;

public class SimpleAES
{
    // Change these keys
    private byte[] Key = { 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
    private byte[] Vector = { 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 };

private ICryptoTransform EncryptorTransform, DecryptorTransform;
private System.Text.UTF8Encoding UTFEncoder;
public SimpleAES()
{
    //This is our encryption method
    RijndaelManaged rm = new RijndaelManaged();
    //Create an encryptor and a decryptor using our encryption method, key, and vector.
    EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector);
    DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector);
    //Used to translate bytes to text and vice versa
    UTFEncoder = new System.Text.UTF8Encoding();
}
/// -------------- Two Utility Methods (not used but may be useful) -----------
/// Generates an encryption key.
static public byte[] GenerateEncryptionKey()
{
    //Generate a Key.
    RijndaelManaged rm = new RijndaelManaged();
    rm.GenerateKey();
    return rm.Key;
}
/// Generates a unique encryption vector
static public byte[] GenerateEncryptionVector()
{
    //Generate a Vector
    RijndaelManaged rm = new RijndaelManaged();
    rm.GenerateIV();
    return rm.IV;
}

/// ----------- The commonly used methods ------------------------------    
/// Encrypt some text and return a string suitable for passing in a URL.
public string EncryptToString(string TextValue)
{
    return ByteArrToString(Encrypt(TextValue));
}
/// Encrypt some text and return an encrypted byte array.
public byte[] Encrypt(string TextValue)
{
    //Translates our text value into a byte array.
    Byte[] bytes = UTFEncoder.GetBytes(TextValue);
    //Used to stream the data in and out of the CryptoStream.
    MemoryStream memoryStream = new MemoryStream();
    /*
     * We will have to write the unencrypted bytes to the stream,
     * then read the encrypted result back from the stream.
     */
    #region Write the decrypted value to the encryption stream
    CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
    cs.Write(bytes, 0, bytes.Length);
    cs.FlushFinalBlock();
    #endregion
    #region Read encrypted value back out of the stream
    memoryStream.Position = 0;
    byte[] encrypted = new byte[memoryStream.Length];
    memoryStream.Read(encrypted, 0, encrypted.Length);
    #endregion
    //Clean up.
    cs.Close();
    memoryStream.Close();
    return encrypted;
}
/// The other side: Decryption methods
public string DecryptString(string EncryptedString)
{
    return Decrypt(StrToByteArray(EncryptedString));
}
/// Decryption when working with byte arrays.    
public string Decrypt(byte[] EncryptedValue)
{
    #region Write the encrypted value to the decryption stream
    MemoryStream encryptedStream = new MemoryStream();
    CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
    decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
    decryptStream.FlushFinalBlock();
    #endregion
    #region Read the decrypted value from the stream.
    encryptedStream.Position = 0;
    Byte[] decryptedBytes = new Byte[encryptedStream.Length];
    encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
    encryptedStream.Close();
    #endregion
    return UTFEncoder.GetString(decryptedBytes);
}
/// Convert a string to a byte array.  NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
//      System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
//      return encoding.GetBytes(str);
// However, this results in character values that cannot be passed in a URL.  So, instead, I just
// lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
public byte[] StrToByteArray(string str)
{
    if (str.Length == 0)
        throw new Exception("Invalid string value in StrToByteArray");
    byte val;
    byte[] byteArr = new byte[str.Length / 3];
    int i = 0;
    int j = 0;
    do
    {
        val = byte.Parse(str.Substring(i, 3));
        byteArr[j++] = val;
        i += 3;
    }
    while (i < str.Length);
    return byteArr;
}
// Same comment as above.  Normally the conversion would use an ASCII encoding in the other direction:
//      System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
//      return enc.GetString(byteArr);    
public string ByteArrToString(byte[] byteArr)
{
    byte val;
    string tempStr = "";
    for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
    {
        val = byteArr[i];
        if (val < (byte)10)
            tempStr += "00" + val.ToString();
        else if (val < (byte)100)
            tempStr += "0" + val.ToString();
        else
            tempStr += val.ToString();
    }
    return tempStr;
}

}

非常感谢大家!

奇怪的加密/解密错误 (C# - AES)

编辑了您提供的代码以按照要求工作。

private static byte[] Key = { 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private static byte[] Vector = { 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 };
private static RijndaelManaged _rijndaelManaged;
static void Main(string[] args)
{
    var allBytes = File.ReadAllBytes("hello.bin");
    _rijndaelManaged = new RijndaelManaged { Key = Key, IV = Vector };
    byte[] encBytes = Encrypt(allBytes, Key, Vector);
    byte[] decBytes = Decrypt(encBytes, Key, Vector);
    using (var mstream = new MemoryStream(decBytes))
    using (var breader = new BinaryReader(mstream))
    {
        Console.WriteLine(breader.ReadString());
    }
}
private static byte[] Decrypt(byte[] encBytes, byte[] key, byte[] vector)
{
    byte[] decBytes;
    using (var mstream = new MemoryStream())
    using (var crypto = new CryptoStream(mstream, _rijndaelManaged.CreateDecryptor(key, vector), CryptoStreamMode.Write))
    {
        crypto.Write(encBytes, 0, encBytes.Length);
        crypto.FlushFinalBlock();
        mstream.Position = 0;
        decBytes = new byte[mstream.Length];
        mstream.Read(decBytes, 0, decBytes.Length);
    }
    return decBytes;
}
private static byte[] Encrypt(byte[] allBytes, byte[] key, byte[] vector)
{
    byte[] encBytes;
    using (var mstream = new MemoryStream())
    using (var crypto = new CryptoStream(mstream, _rijndaelManaged.CreateEncryptor(key, vector), CryptoStreamMode.Write))
    {
        crypto.Write(allBytes, 0, allBytes.Length);
        crypto.FlushFinalBlock();
        mstream.Position = 0;
        encBytes = new byte[mstream.Length];
        mstream.Read(encBytes, 0, encBytes.Length);
    }
    return encBytes;
}

正如Eoin所解释的那样,您所要做的就是删除将字节转换回字符串的行。我发布了整个工作代码,因为我不确定输入文件是否是二进制文件导致任何问题。其实不然。

Evan,

我想你可能在这里把事情复杂化了。如果不做任何检查,我认为问题出在你StringToByteByteToString方法上。您实际上应该使用其中一个System.Text.Encoding类进行字符串>字节转换(就像 AES 类一样)

但是,如果您只需要将源字节[]加密为目标字节[],则可以执行以下操作,完全忘记字符串。

更改 SimpleAES 加密和解密签名,如下所示

public byte[] Encrypt(Byte[] bytes) //Change To take in a byte[]
{
    //Translates our text value into a byte array.
    //Byte[] bytes = UTFEncoder.GetBytes(TextValue); <-- REMOVE THIS LINE
    ... do stuff with `bytes`
}
public byte[] Decrypt(byte[] EncryptedValue) //now returns a byte array instead of a string
{
    //return UTFEncoder.GetString(decryptedBytes); <-- JUST RETURN THE BYTE[] INSTEAD
    return decryptedBytes;
}

所以现在你只需输入它并输入byte [],然后接收一个加密的byte []

可以使用以下命令在调试器中验证这一点。

SimpleAES sa = new SimpleAES();
byte[] plainBytes = new byte[] { 0x01, 0xFF, 0x53, 0xC2};
byte[] encBytes = sa.Encrypt(plainBytes);
byte[] decBytes = sa.Decrypt(encBytes);
//BREAK HERE
//Compare the values of decBytes & plainBytes