开发者

Odd Encryption/Decryption Error (C# - AES)

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!


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.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜