.NET Core (C#) 中的 AES-256-CBC [英] AES-256-CBC in .NET Core (C#)

查看:39
本文介绍了.NET Core (C#) 中的 AES-256-CBC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找 C# 代码来重现以下 openssl 命令.

I am searching for C# Code to reproduce the following openssl command.

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

附加信息:

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

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

I have been trying out various examples found by searching the web. The problem is, that all of these examples require an IV (initialization vector). Unfortunately, I don't have an IV and no one on the team knows what this is or how it could be defined. The openssl command does not seem to need one, so I am a bit confused about this.

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

Currently, the code, I am trying with, looks as follows:

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;
    }
}

代码失败,说我的 byte[256] 密钥对于这种算法的长度有误.

The code fails saying that my byte[256] key has the wrong length for this kind of algorithm.

感谢您对此的任何帮助!

Thanks for any help with this!

干杯,迈克

推荐答案

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

The posted OpenSSL statement uses the -pass file: option and thus a passphrase (which is read from a file), see openssl enc. This causes the encryption process to first generate a random 8 bytes salt and then, together with the passphrase, derive a 32 bytes key and 16 bytes IV using the (not very secure) proprietary OpenSSL function EVP_BytesToKey. This function uses several parameters, e.g. a digest and an iteration count. The default digest for key derivation is MD5 and the iteration count is 1. Note that OpenSSL version 1.1.0 and later uses SHA256 as default digest, i.e. depending on the OpenSSL version used to generate the ciphertext, the appropriate digest must be used for decryption. Preceding the ciphertext is a block whose first 8 bytes is the ASCII encoding of Salted__, followed by the 8 bytes salt.

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

Therefore, the decryption must first determine the salt. Based on the salt, together with the passphrase, key and IV must be derived and then the rest of the encrypted data can be decrypted. Thus, first of all an implementation of EVP_BytesToKey in C# is required, e.g. here. Then a possible implementation could be (using MD5 as digest):

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;
}

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

Note that the 2nd parameter of DecryptAesCbc is the passphrase (as string) and not the key (as byte[]). Also note that StreamReader uses an encoding (UTF-8 by default), which requires compatible data (i.e. text data, but this should be met for csv files). Otherwise (i.e. for binary data as opposed to text data) StreamReader must not be used.

这篇关于.NET Core (C#) 中的 AES-256-CBC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆