首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RijndaelManaged返回空结果

RijndaelManaged返回空结果
EN

Stack Overflow用户
提问于 2020-08-12 18:24:07
回答 1查看 142关注 0票数 4

问题

我想用RijndaelManaged解密加密的数据,但是结果总是空的(要么是"",要么是数据长度为零的字节数组)。

所有参数、salt和数据都是正确的,CryptoHelper.CreateRijndaelManagedAES在加密方法中得到完全相同的调用(这会产生良好的输出)。

我唯一能想到的就是我用错了溪流,但我不知道为什么.

代码语言:javascript
复制
public static RijndaelManaged CreateRijndaelManagedAES(byte[] passwordHash, byte[] salt)
{
    RijndaelManaged aes = new RijndaelManaged
    {
        KeySize = 256,
        BlockSize = 128,
        Padding = PaddingMode.PKCS7,
        Mode = CipherMode.CBC
    };

    // Derive a key of the full Argon2 string (contains also meta data)
    using Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordHash, salt, 10);
    aes.Key = key.GetBytes(aes.KeySize / 8);
    aes.IV = key.GetBytes(aes.BlockSize / 8);

    return aes;
}

public static async Task<string> EncryptDataAsync(string plainData, byte[] passwordHash, int saltSize)
{
    return await Task.Run(async () =>
    {
        // Generate a random salt
        byte[] salt = CryptoHelper.GenerateRandomSalt(saltSize);

        // Write the salt unencrypted
        using MemoryStream memoryStream = new MemoryStream();
        await memoryStream.WriteAsync(salt);

        // Encrypt the data and write the result to the stream
        using RijndaelManaged aes = CryptoHelper.CreateRijndaelManagedAES(passwordHash, salt);
        using CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
        using StreamWriter streamWriter = new StreamWriter(cryptoStream);
        await streamWriter.WriteAsync(plainData);
        cryptoStream.FlushFinalBlock();

        return ENCRYPTED_MAGIC + Convert.ToBase64String(memoryStream.ToArray());
    });
}

public static async Task<string> DecryptDataAsync(string encryptedData, byte[] passwordHash, int saltSize)
{
    if (!HasValidMagicBytes(encryptedData))
    {
        throw new ArgumentException("The given data isn't encrypted");
    }

    return await Task.Run(async () =>
    {
        byte[] saltAndData = Convert.FromBase64String(encryptedData.Substring(ENCRYPTED_MAGIC.Length));
        byte[] salt = saltAndData.Take(saltSize).ToArray();
        byte[] data = saltAndData.TakeLast(saltAndData.Length - saltSize).ToArray();

        // Decrypt the data and return the result
        using MemoryStream memoryStream = new MemoryStream(data);
        using RijndaelManaged aes = CryptoHelper.CreateRijndaelManagedAES(passwordHash, salt);
        using CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
        using StreamReader streamReader = new StreamReader(cryptoStream);
        return await streamReader.ReadToEndAsync();
    });
}

安全通知

如果您向Rfc2898DeriveBytes传递密码,请不要只使用10次迭代(如我所做的)。由于性能原因,我事先从密码中获得了一个密钥,并将结果传递给CreateRijndaelManagedAES函数。

如果您想使用带有密码的Rfc2898DeriveBytes,则至少应该使用50000次迭代(截止到2020年)。

移栽

迭代参数基本上是一个成本参数。迭代次数越多,攻击者就越难强行执行派生密码(因为他需要更多的计算能力/时间)。NIST在2017年制作了一个出版,它规定您应该尽可能多地使用环境所能处理的迭代,但至少要使用10000次。我再也找不到消息来源了,但我记得读过,你目前至少应该使用50000 (由于未来的安全)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-13 09:26:41

问题在EncryptDataAsync方法中,即加密(在DecryptDataAsync中,即解密中,错误只会变得明显)。这是因为在调用StreamWriter之前必须先刷新memoryStream.ToArray()。此调用必须在此之前执行。

代码语言:javascript
复制
...
cryptoStream.FlushFinalBlock(); 
...

即:

代码语言:javascript
复制
...
streamWriter.Flush();
cryptoStream.FlushFinalBlock(); 
...

或者另一种

代码语言:javascript
复制
...
streamWriter.Close();
...

这会刷新/关闭两个流,请参见StreamWriter.Flush()StreamWriter.Close()

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63382645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档