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

时间:2011-05-14 22:14:52

标签: c# encryption utf-8 aes

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

首先,我将解释我想要做出的改变。

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

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

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

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

}

非常感谢大家!

2 个答案:

答案 0 :(得分:1)

根据要求编辑您提供的代码。

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

答案 1 :(得分:1)

埃文,

我认为你可能会在这里复杂化。在没有进行任何检查的情况下,我认为问题在于您的StringToByte&amp; ByteToString方法。您应该使用其中一个System.Text.Encoding类进行字符串 - >字节转换(就像AES类一样)

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

更改SimpleAES加密&amp;解密签名如下

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