我正在尝试通过 HTTP 标头将用户名发送到我的服务,并且我希望使用 AES 对其进行加密。 (是的,这可以以更好的方式完成)
最终解密的字符串始终为空。
加密:
using var aes = Aes.Create();
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.GenerateIV();
aes.Key = SHA256.HashData(Encoding.Unicode.GetBytes(PK));
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using MemoryStream memoryStream = new MemoryStream();
using CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
using StreamWriter streamWriter = new StreamWriter(cryptoStream, Encoding.Unicode);
string payload = UserProvider.User;
streamWriter.Write(payload);
cryptoStream.FlushFinalBlock();
byte[] array = memoryStream.ToArray();
string encryptedString = Convert.ToBase64String(array);
string ivString = Convert.ToBase64String(aes.IV);
_client.AddDefaultHeader("user", encryptedString);
_client.AddDefaultHeader("iv", ivString);
解密:
internal static class Authentication
{
private const string PK = "MySecretKey";
public static string DecryptUser(string encrypted, string iv)
{
using (var aes = Aes.Create())
using (var sha = SHA256.Create())
{
byte[] pkBytes = Encoding.Unicode.GetBytes(PK);
byte[] pkHash = sha.ComputeHash(pkBytes);
byte[] ivBytes = Convert.FromBase64String(iv);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.Key = pkHash;
aes.IV = ivBytes;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] cipher = Convert.FromBase64String(encrypted);
using (MemoryStream memoryStream = new MemoryStream(cipher))
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (StreamReader streamReader = new StreamReader(cryptoStream))
{
string user = streamReader.ReadToEnd();
if (user.IsNullOrWhiteSpace()) throw new Exception("Authentication failed.");
return user;
}
}
}
}
我已经检查过的事情:
ReadToEnd()
使cryptoStream.HasFlushedFinalBlock
从假变为真我在服务器上运行 .NET Framework 4.8(解密端),在客户端上运行 .NET 8(加密端)。
编辑:我编写了一个小型 xUnit 测试,完全排除了 Base64/HTTP 部分,但它仍然不起作用。
public class UnitTest1
{
[Fact]
public void TestMethod1()
{
byte[] buffer = new byte[1024];
using (var aes = Aes.Create())
using (var sha = SHA256.Create())
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.Key = sha.ComputeHash(Encoding.Unicode.GetBytes("Password"));
using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
using (MemoryStream memoryStream = new MemoryStream())
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
using (StreamWriter streamWriter = new StreamWriter(cryptoStream, Encoding.Unicode))
{
string payload = "username";
streamWriter.Write(payload);
cryptoStream.FlushFinalBlock();
buffer = memoryStream.ToArray();
Assert.NotEmpty(buffer);
}
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
using (MemoryStream memoryStream = new MemoryStream(buffer))
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (StreamReader streamReader = new StreamReader(cryptoStream, Encoding.Unicode))
{
string user = streamReader.ReadToEnd();
Assert.True(streamReader.EndOfStream);
Assert.True(cryptoStream.HasFlushedFinalBlock);
Assert.Equal("username", user);
}
}
}
}
事实证明,对
cryptoStream.FlushFinalBlock()
的调用不足以确保有效负载实际上已加密。
我必须添加对
streamWriter.Flush()
before 的调用,以实际将字节从 StreamWriter 的内部缓冲区传递到他的内部 Stream。
或者,我也可以打电话给
streamWriter.Close()
。
// Works
streamWriter.Write(payload);
streamWriter.Flush();
cryptoStream.FlushFinalBlock();
// Works
streamWriter.Write(payload);
streamWriter.Close();
// Does not work!
streamWriter.Write(payload);
cryptoStream.FlushFinalBlock();
// Does not work!
streamWriter.Write(payload);
streamWriter.Flush();
cryptoStream.Flush();