C# – AES加密解密错误:解密中的最后一个块不完整

huangapple go评论79阅读模式
英文:

C# - AES encrypt-decrypt error : last block incomplete in decryption

问题

以下是您提供的代码的中文翻译:

我正在尝试使用AES加密和解密字符串,一切都在同一台机器上运行正常,但当我在不同的机器上使用时,首先加密然后另一台机器上解密时,我遇到了这个错误:解密中的最后一个块不完整。

这是我的代码:

public string Encrypt1(string plainText)
{
    string key = _appSettings.JwtSecret;
    byte[] iv = new byte[16];
    byte[] array;

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;

        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
                {
                    streamWriter.Write(plainText);
                }

                array = memoryStream.ToArray();
            }
        }
    }

    return Convert.ToBase64String(array);
}

public string Decrypt1(string cipherText)
{
    string key = _appSettings.JwtSecret;
    byte[] iv = new byte[16];
    byte[] buffer = Convert.FromBase64String(cipherText);

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

        using (MemoryStream memoryStream = new MemoryStream(buffer))
        {
            using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }
    }
}

请注意,我仅提供了您代码的中文翻译,没有包括问题的回答或额外的内容。

英文:

I'm trying to encrypt and decrypt a string using AES everything. Everything work well when I'm using the same machine, but when I'm using different machine the, first to encrypt and another one to decrypt I have this error : last block incomplete in decryption.

This is my code :

public string Encrypt1(string plainText)

{
    string key = _appSettings.JwtSecret;
    byte[] iv = new byte[16];
    byte[] array;

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;

        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
                {
                    streamWriter.Write(plainText);
                }

                array = memoryStream.ToArray();
            }
        }
    }

    return Convert.ToBase64String(array);
}

public string Decrypt1(string cipherText)
{
    string key = _appSettings.JwtSecret;
    byte[] iv = new byte[16];
    byte[] buffer = Convert.FromBase64String(cipherText);

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

        using (MemoryStream memoryStream = new MemoryStream(buffer))
        {
            using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }
    }
}

I don't know if there is somthing wrong with my code. I tryied many differents codes but I still have the same issue.

答案1

得分: 2

你的示例在使用 .Net Framework 4.8 时对我有效。

然而,你在使用初始化向量时存在问题。IV 应该是随机值,而不仅仅是零,但它不是秘密,因此可以安全地将其以明文形式发送,例如添加到消息的前面:

[Test]
public void test()
{
    var input = string.Join(Environment.NewLine, Enumerable.Range(0, 4096).Select(i => i.ToString()));
    var str = Encrypt1(input);
    var result = Decrypt1(str);
    Assert.AreEqual(result, input);
}
public string Encrypt1(string plainText)
{
    byte[] array;
    using (Aes aes = Aes.Create())
    {
        aes.Key = new byte[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,  12, 13, 14, 15, 16};
        var iv = aes.IV;
        var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        using (var memoryStream = new MemoryStream())
        {
            memoryStream.Write(iv, 0, iv.Length);
            using (var cryptoStream = new CryptoStream( memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (var streamWriter = new StreamWriter( cryptoStream, Encoding.UTF8))
                {
                    streamWriter.Write(plainText);
                }
                Assert.IsTrue(cryptoStream.HasFlushedFinalBlock);
                array = memoryStream.ToArray();
            }
        }
    }
    return Convert.ToBase64String(array);
}

public string Decrypt1(string cipherText)
{
    byte[] iv = new byte[16];
    byte[] buffer = Convert.FromBase64String(cipherText);

    using (Aes aes = Aes.Create())
    {
        aes.Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
        using (var memoryStream = new MemoryStream(buffer))
        {
            memoryStream.Read(iv, 0, iv.Length);
            aes.IV = iv;
            var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
            {
                using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }
    }
}

你的错误消息暗示了最后一个加密块可能存在问题,可能是由于处理流的问题引起的。加密流需要被释放,或者在使用结果之前显式调用 FlushFinalBlock。这应该StreamWriter 被释放时完成,但我找不到任何文档来确认这一点,而且这可能取决于 .NET 版本。

我建议在 memoryStream.ToArray() 之前添加 Assert.IsTrue(cryptoStream.HasFlushedFinalBlock);。如果失败,你需要插入一个调用 FlushFinalBlock

英文:

Your example works fine for me using .Net framework 4.8.

However, you are using the initialization vector incorrectly. The IV should be random value, not just zeroes, but it is not secret, so it is fine to send this in clear text, for example prepended to the message:

[Test]
public void test()
{
    var input = string.Join(Environment.NewLine, Enumerable.Range(0, 4096).Select(i => i.ToString()) );
    var str = Encrypt1(input);
    var result = Decrypt1(str);
    Assert.AreEqual(result, input);
}
public string Encrypt1(string plainText)
{
    byte[] array;
    using (Aes aes = Aes.Create())
    {
        aes.Key = new byte[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,  12, 13, 14, 15, 16};
        var iv = aes.IV;
        var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        using (var memoryStream = new MemoryStream())
        {
            memoryStream.Write(iv, 0, iv.Length);
            using (var cryptoStream = new CryptoStream( memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (var streamWriter = new StreamWriter( cryptoStream, Encoding.UTF8))
                {
                    streamWriter.Write(plainText);
                }
                Assert.IsTrue(cryptoStream.HasFlushedFinalBlock);
                array = memoryStream.ToArray();
            }
        }
    }
    return Convert.ToBase64String(array);
}

public string Decrypt1(string cipherText)
{
    byte[] iv = new byte[16];
    byte[] buffer = Convert.FromBase64String(cipherText);

    using (Aes aes = Aes.Create())
    {
        aes.Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
        using (var memoryStream = new MemoryStream(buffer))
        {
            memoryStream.Read(iv, 0, iv.Length);
            aes.IV = iv;
            var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
            {
                using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }
    }
}

Your error message suggest an issue with the final encryption block, possibly caused by an issue with disposing streams. The crypto stream needs to be disposed, or have an explicit call to FlushFinalBlock before the result is used. This should be done by StreamWriter when it is disposed, but I cannot find any documentation to confirm this, and it is possible that this could depend on the .net version.

I would suggest adding Assert.IsTrue(cryptoStream.HasFlushedFinalBlock); before memoryStream.ToArray(). If that fails you need to insert a call to FlushFinalBlock.

huangapple
  • 本文由 发表于 2023年4月17日 16:05:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76032931.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定