.NET Core 中的 AES-256-CBC (C#)

Mik*_*J82 2 .net c# aes cbc-mode .net-core

我正在搜索 C# 代码来重现以下 openssl 命令。

openssl enc -d -aes-256-cbc -in my_encrypted_file.csv.enc -out my_decrypted_file.csv -pass file:key.bin

附加信息:

  • 加密文件以 byte[] 形式呈现
  • key.bin 是一个长度为 256 的 byte[](密钥是通过对另一个文件进行更简单的解密获得的,我设法用 C# 实现了该文件)。

我一直在尝试通过搜索网络找到的各种示例。问题是,所有这些例子都需要 IV(初始化向量)。不幸的是,我没有 IV,团队中没有人知道这是什么或如何定义它。openssl 命令似乎不需要一个,所以我对此有点困惑。

目前,我正在尝试使用的代码如下所示:

public static string DecryptAesCbc(byte[] cipheredData, byte[] key)
{
    string decrypted;

    System.Security.Cryptography.Aes aes = System.Security.Cryptography.Aes.Create();
    aes.KeySize = 256;
    aes.Key = key;
    byte[] iv = new byte[aes.BlockSize / 8];
    aes.IV = iv;
    aes.Mode = CipherMode.CBC;

    ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);

    using (MemoryStream ms = new MemoryStream(cipheredData))
    {
        using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                decrypted = sr.ReadToEnd();
            }
        }
        
        return decrypted;
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码失败,表明我的 byte[256] 密钥对于此类算法的长度错误。

感谢您对此的任何帮助!

干杯,迈克

Top*_*aco 7

发布的 OpenSSL 语句使用该-pass file:选项以及密码(从文件中读取),请参阅openssl enc。这导致加密过程首先生成随机的8 字节盐,然后与密码一起使用(不是很安全)专有的 OpenSSL 函数导出 32 字节密钥和 16 字节 IV EVP_BytesToKey。该函数使用多个参数,例如摘要和迭代计数。密钥派生的默认摘要为MD5,迭代计数为 1。请注意,OpenSSL 版本1.1.0及更高版本使用SHA256作为默认摘要,即根据用于生成密文的 OpenSSL 版本,必须使用适当的摘要进行解密。密文之前是一个块,其前 8 个字节是 的 ASCII 编码Salted__,后面是 8 个字节的盐。

因此,解密首先要确定盐。基于盐,必须与密码一起导出密钥和 IV,然后才能解密其余的加密数据。因此,首先EVP_BytesToKey需要在 C# 中实现,例如here。那么一个可能的实现可以是(使用MD5作为摘要):

public static string DecryptAesCbc(byte[] cipheredData, string passphrase)
{
    string decrypted = null;

    using (MemoryStream ms = new MemoryStream(cipheredData))
    {
        // Get salt
        byte[] salt = new byte[8];
        ms.Seek(8, SeekOrigin.Begin);
        ms.Read(salt, 0, 8);

        // Derive key and IV
        OpenSslCompat.OpenSslCompatDeriveBytes db = new OpenSslCompat.OpenSslCompatDeriveBytes(passphrase, salt, "MD5", 1);
        byte[] key = db.GetBytes(32);
        byte[] iv = db.GetBytes(16);

        using (Aes aes = Aes.Create())
        {
            aes.Padding = PaddingMode.PKCS7;
            aes.Mode = CipherMode.CBC;
            aes.Key = key;
            aes.IV = iv;

            // Decrypt
            ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
            using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
            {
                using (StreamReader sr = new StreamReader(cs, Encoding.UTF8))
                {
                    decrypted = sr.ReadToEnd();
                }
            }
        }
    }

    return decrypted;
}
Run Code Online (Sandbox Code Playgroud)

请注意, 的第二个参数DecryptAesCbc是密码(as string)而不是密钥(as byte[])。另请注意,StreamReader使用编码(默认为 UTF-8),这需要兼容的数据(即文本数据,但这对于csv文件应该满足)。否则(即对于二进制数据而不是文本数据)StreamReader不得使用。