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

发布于 2024-11-07 22:45:56 字数 7179 浏览 0 评论 0原文

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

首先,我将解释我正在尝试做出的改变。

1)我想将 Encrypt 函数的参数从字符串更改为字节数组。我认为这将是非常简单的任务(只需快速执行 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;
}

}

非常感谢大家!

I found the following AES encryption class from another question here. The class (as is) works great, however, I have been trying to modify the class to my liking which is where I have encountered these errors. Please note that it is a binary file that I am trying to encrypt.

First I will explain the changes I am trying to make.

1) I want to change the parameter of the Encrypt function from a string, to a byte array. I thought this would be very simple task (just do a quick File.ReadAllBytes and pass the byte array to the Encrypt function) but this was not the case.

2) I want the decrypt function to return a byte array. Same issue as above, I can't get this to work properly.

I was hoping that someone would be able to give me a working example of encrypting and decrypting a binary file similar to what I have setup below:

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();
    }

Here is the AES class I am using:

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;
}

}

Thank you very much everyone!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橪书 2024-11-14 22:45:56

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

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 所解释的,您所要做的就是删除将字节转换回字符串的行。我发布了整个工作代码,因为我不确定输入文件是二进制文件是否会导致任何问题。事实并非如此。

Edited the code you provided to work as per the requirements.

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;
}

As Eoin explained, all you had to do was remove the line which converted the bytes back to the string. I posted the entire working code as I was not sure whether the input file being a binary file was causing any issues. It doesnt.

音栖息无 2024-11-14 22:45:56

埃文,

我认为你可能把事情复杂化了。在不进行任何检查的情况下,我认为问题出在您的 StringToByte & 上。 ByteToString 方法。您确实应该使用 System.Text.Encoding 类之一进行字符串->字节转换(就像 AES 类所做的那样)

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

更改 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

Evan,

I think you might be over complicating things here. And without doing any checking, I think the problem lies with your StringToByte & ByteToString methods. You should really be using one of the System.Text.Encoding classes for string->byte conversion (just like the AES Class does)

But if you only need to encrypt a source byte[] to a destination byte[] you can do the following and forget about strings completely.

Change the SimpleAES Encrypt & Decrypt Signatures as follows

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;
}

So now you just feed it and input byte [] and receive an encrypted byte [] back.

You can verify this in the debugger using.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文