奇怪的加密/解密错误(C# - AES)
我从另一个问题中找到了以下 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑您提供的代码以按照要求工作。
正如 Eoin 所解释的,您所要做的就是删除将字节转换回字符串的行。我发布了整个工作代码,因为我不确定输入文件是二进制文件是否会导致任何问题。事实并非如此。
Edited the code you provided to work as per the requirements.
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.
埃文,
我认为你可能把事情复杂化了。在不进行任何检查的情况下,我认为问题出在您的
StringToByte
& 上。ByteToString
方法。您确实应该使用 System.Text.Encoding 类之一进行字符串->字节转换(就像 AES 类所做的那样)但是如果您只需要将源 byte[] 加密为目标 byte[] 您可以执行以下操作并完全忘记字符串。
更改 SimpleAES 加密和解密签名如下
现在您只需输入
byte []
即可收到加密的byte []
返回。您可以在调试器中使用来验证这一点。
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 theSystem.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
So now you just feed it and input
byte []
and receive an encryptedbyte []
back.You can verify this in the debugger using.