.NET Framework 中的 AES 解密失败

问题描述 投票:0回答:1

我正在尝试通过 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;
            }
        }
    }
}

我已经检查过的事情:

  • CipherMode 正确
  • PaddingMode 正确
  • 我收到的 Base64 字符串不为空或损坏
  • 我尝试在 MemoryStream 上寻找 0
  • 我尝试发送更长的内容,看看问题是否出在解密器中的最小块大小
  • 我尝试将 CrytoStream 复制到另一个 MemoryStream 中,但生成的缓冲区为空
  • 跨过
    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);
            }
        }
    }
}
c# .net cryptography aes
1个回答
0
投票

事实证明,对

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();
© www.soinside.com 2019 - 2024. All rights reserved.