Нечетная ошибка шифрования / дешифрования (C # - AES) - PullRequest
1 голос
/ 15 мая 2011

Я нашел следующий класс шифрования 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;
}

}

Большое спасибо всем!

Ответы [ 2 ]

1 голос
/ 15 мая 2011

Evan,

Я думаю, что вы, возможно, слишком усложняете вещи здесь. И без каких-либо проверок, я думаю, что проблема заключается в ваших StringToByte & ByteToString методах. Вы действительно должны использовать один из System.Text.Encoding классов для преобразования строк-> байтов (как это делает класс AES)

Но если вам нужно только зашифровать исходный байт [] до целевого байта [], вы можете сделать следующее и полностью забыть о строках.

Измените подписи SimpleAES Encrypt & Decrypt следующим образом

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
1 голос
/ 15 мая 2011

Отредактировал предоставленный вами код для работы в соответствии с требованиями.

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

Как объяснил Эойн, все, что вам нужно было сделать, это удалить строку, которая преобразовала байты обратно в строку. Я опубликовал весь рабочий код, так как не был уверен, что входной файл, являющийся двоичным файлом, вызывает какие-либо проблемы. Это не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...