C# AES 加密行为异常
C# AES encryption behaving strangely
我正在尝试使用这段代码在 C# 中加密字符串:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
// Write all data to the stream
swEncrypt.Write(plainText);
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
这主要基于此处找到的样本:example。
然而,结果有点 st运行ge 和不可预测 - 一次我 运行 代码并得到一些字符串作为结果,另一次结果字符串(和 msEncrypt
流) 是空的,有一次应用程序甚至冻结了。我不明白这是什么问题。
编辑:
我只是再次 运行 代码,在这一行:
aesAlg.Key = Key;
发生了一些事情运行ge,我得到了这个错误:
下面是我实际调用此方法的方式:
public static class Authentication
{
...
private static readonly AesEncryption aes = new AesEncryption();
public static string GenerateToken()
{
AuthenticationData data = new AuthenticationData()
{
// some data
};
string serialized = JsonConvert.SerializeObject(data);
return AesEncryption.AesEncrypt(serialized, aes.Key, aes.IV);
}
}
可能每次调用AesEncrypt方法时传入的key和IV都不一样。
对我来说,这个例子很好用。
static void Main(string[] args)
{
Aes aesAlg = Aes.Create();
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
Console.ReadKey();
}
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
Console.WriteLine(BitConverter.ToString(msEncrypt.ToArray()));
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
}
}
}
缓冲区和刷新流可能有问题。
尝试在 msEncript.ToArray()
之前仅 swEncript
使用范围
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
// Write all data to the stream
swEncrypt.Write(plainText);
}
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
这段代码有两个问题。
SteamWriter
在使用流之前未关闭。也没有调用 StreamWriter.Flush。 StreamWriter 在内部使用缓冲区并将其写出到
流满时。
StreamWriter 不知道它正在写入
一个 MemoryStream,所有的流对它来说都是一样的。鉴于有多小
在大多数示例中都是明文,在尝试之前不会发生刷新
从内存流中读取数据。
- UTF8 仅支持一组有限的字节序列。好的加密算法虽然会生成基本上随机的序列。其中一些不会对应于任何有效的 UTF8 序列。将二进制数据编码为文本的最常见方法之一是使用 Base64 编码。这就是大多数加密或散列样本所显示的内容。
代码应更改为:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
swEncrypt.Write(plainText);
//CHANGES HERE
swEncrypt.Flush();
return Convert.ToBase64String(msEncrypt.ToArray());
}
示例没有遇到此问题,因为它使用显式 using
块,因此在使用内存流 之前 关闭编写器:
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
Visual Studio 和 Resharper 都不建议在这种情况下使用 using
语句,因为 writer
显然在最里面的块中关闭。
不要混用 using
样式
您可以混合使用块和语句,例如:
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
考虑到已经造成的混乱,您可能不应该这样做。代码并没有那么清晰,它已经引起了问题。将来看到相同代码的其他人也可能会感到困惑,并使用糟糕的重构
我正在尝试使用这段代码在 C# 中加密字符串:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
// Write all data to the stream
swEncrypt.Write(plainText);
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
这主要基于此处找到的样本:example。
然而,结果有点 st运行ge 和不可预测 - 一次我 运行 代码并得到一些字符串作为结果,另一次结果字符串(和 msEncrypt
流) 是空的,有一次应用程序甚至冻结了。我不明白这是什么问题。
编辑: 我只是再次 运行 代码,在这一行:
aesAlg.Key = Key;
发生了一些事情运行ge,我得到了这个错误:
下面是我实际调用此方法的方式:
public static class Authentication
{
...
private static readonly AesEncryption aes = new AesEncryption();
public static string GenerateToken()
{
AuthenticationData data = new AuthenticationData()
{
// some data
};
string serialized = JsonConvert.SerializeObject(data);
return AesEncryption.AesEncrypt(serialized, aes.Key, aes.IV);
}
}
可能每次调用AesEncrypt方法时传入的key和IV都不一样。 对我来说,这个例子很好用。
static void Main(string[] args)
{
Aes aesAlg = Aes.Create();
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
Console.ReadKey();
}
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
Console.WriteLine(BitConverter.ToString(msEncrypt.ToArray()));
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
}
}
}
缓冲区和刷新流可能有问题。
尝试在 msEncript.ToArray()
swEncript
使用范围
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
// Write all data to the stream
swEncrypt.Write(plainText);
}
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
这段代码有两个问题。
SteamWriter
在使用流之前未关闭。也没有调用 StreamWriter.Flush。 StreamWriter 在内部使用缓冲区并将其写出到 流满时。StreamWriter 不知道它正在写入 一个 MemoryStream,所有的流对它来说都是一样的。鉴于有多小 在大多数示例中都是明文,在尝试之前不会发生刷新 从内存流中读取数据。
- UTF8 仅支持一组有限的字节序列。好的加密算法虽然会生成基本上随机的序列。其中一些不会对应于任何有效的 UTF8 序列。将二进制数据编码为文本的最常见方法之一是使用 Base64 编码。这就是大多数加密或散列样本所显示的内容。
代码应更改为:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
swEncrypt.Write(plainText);
//CHANGES HERE
swEncrypt.Flush();
return Convert.ToBase64String(msEncrypt.ToArray());
}
示例没有遇到此问题,因为它使用显式 using
块,因此在使用内存流 之前 关闭编写器:
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
Visual Studio 和 Resharper 都不建议在这种情况下使用 using
语句,因为 writer
显然在最里面的块中关闭。
不要混用 using
样式
您可以混合使用块和语句,例如:
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
考虑到已经造成的混乱,您可能不应该这样做。代码并没有那么清晰,它已经引起了问题。将来看到相同代码的其他人也可能会感到困惑,并使用糟糕的重构