C# 版本的 OpenSSL EVP_BytesToKey 方法?

Posted

技术标签:

【中文标题】C# 版本的 OpenSSL EVP_BytesToKey 方法?【英文标题】:C# version of OpenSSL EVP_BytesToKey method? 【发布时间】:2011-12-21 22:28:18 【问题描述】:

我正在寻找 OpenSSL EVP_BytesToKey 函数的直接 .NET 实现。我发现的最接近的是 System.Security.Cryptography.PasswordDeriveBytes 类(和 Rfc2898DeriveBytes),但它似乎是 slightly different 并且不会生成相同的 keyiv 作为 EVP_BytesToKey。

我还发现了这个implementation,这似乎是一个好的开始,但没有考虑迭代次数。

我知道有 OpenSSL.NET,但它只是原生 openssl DLL 的包装,而不是“真正的”.NET 实现。

【问题讨论】:

【参考方案1】:

我找到了 EVP_BytesToKey 方法的伪代码解释(在 openssl 源的/doc/ssleay.txt 中):

/* M[] is an array of message digests
 * MD() is the message digest function */
M[0]=MD(data . salt);
for (i=1; i<count; i++) M[0]=MD(M[0]);

i=1
while (data still needed for key and iv)
    
    M[i]=MD(M[i-1] . data . salt);
    for (i=1; i<count; i++) M[i]=MD(M[i]);
    i++;
    

If the salt is NULL, it is not used.
The digests are concatenated together.
M = M[0] . M[1] . M[2] .......

因此,基于此,我能够提出这个 C# 方法(这似乎适用于我的目的,并假定 32 字节密钥和 16 字节 iv):

private static void DeriveKeyAndIV(byte[] data, byte[] salt, int count, out byte[] key, out byte[] iv)

    List<byte> hashList = new List<byte>();
    byte[] currentHash = new byte[0];

    int preHashLength = data.Length + ((salt != null) ? salt.Length : 0);
    byte[] preHash = new byte[preHashLength];

    System.Buffer.BlockCopy(data, 0, preHash, 0, data.Length);
    if (salt != null)
        System.Buffer.BlockCopy(salt, 0, preHash, data.Length, salt.Length);

    MD5 hash = MD5.Create();
    currentHash = hash.ComputeHash(preHash);          

    for (int i = 1; i < count; i++)
    
        currentHash = hash.ComputeHash(currentHash);            
    

    hashList.AddRange(currentHash);

    while (hashList.Count < 48) // for 32-byte key and 16-byte iv
    
        preHashLength = currentHash.Length + data.Length + ((salt != null) ? salt.Length : 0);
        preHash = new byte[preHashLength];

        System.Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
        System.Buffer.BlockCopy(data, 0, preHash, currentHash.Length, data.Length);
        if (salt != null)
            System.Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + data.Length, salt.Length);

        currentHash = hash.ComputeHash(preHash);            

        for (int i = 1; i < count; i++)
        
            currentHash = hash.ComputeHash(currentHash);
        

        hashList.AddRange(currentHash);
    
    hash.Clear();
    key = new byte[32];
    iv = new byte[16];
    hashList.CopyTo(0, key, 0, 32);
    hashList.CopyTo(32, iv, 0, 16);

更新:这里的实现大致相同,但使用 .NET DeriveBytes 接口:https://gist.github.com/1339719


OpenSSL 1.1.0c changed the digest algorithm 用于一些内部组件。以前使用MD5,1.1.0改用SHA256。请注意,EVP_BytesToKeyopenssl enc 等命令中的更改不会影响您。

【讨论】:

谢谢!还要记住,OpenSSL 的默认运行使用iterations=1

以上是关于C# 版本的 OpenSSL EVP_BytesToKey 方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 OpenSSL ECDSA 密钥加载到 C# 中?

解密用 PHP openssl_encrypt 加密的 C# 中的字符串

如何支持自定义安装的高版本openssl库

openssl-1.0.1g以后的版本都有哪些

OpenSSL 标头版本!= 影响 APNS 的 HTTP/2 的 OpenSSL 库版本

php升级openssl扩展,swoole升级openssl扩展,linux安装openssl版本