C#版本的OpenSSL EVP_BytesToKey方法?版本、方法、OpenSSL、EVP_BytesToKey

2023-09-02 01:30:55 作者:智商要欠费i

我在寻找直线上升.NET实现的OpenSSL的 EVP_BytesToKey 功能。我发现的最接近的是 System.Security程序。 Cryptography.PasswordDeriveBytes 类( Rfc2898DeriveBytes ),但它似乎是slightly不同并不会产生相同的键和第四作为EVP_BytesToKey。

I'm looking for straight-up .NET implementation of the OpenSSL EVP_BytesToKey function. The closest thing I've found is the System.Security.Cryptography.PasswordDeriveBytes class (and Rfc2898DeriveBytes) but it seems to be slightly different and doesn't generate the same key and iv as EVP_BytesToKey.

我也发现了这个implementation这似乎是一个良好的开端,但并没有考虑到迭代次数。

I also found this implementation which seems like a good start but doesn't take into account iteration count.

我知道还有的OpenSSL.NET,但它只是一个围绕本地的OpenSSL DLL的包装不是真正的.NET实现。

I realize there's OpenSSL.NET but it's just a wrapper around the native openssl DLLs not a "real" .NET implementation.

推荐答案

我发现在 EVP_BytesToKey 方法的这一伪code解释(中的 / DOC / ssleay.txt OpenSSL的源):

I found this pseudo-code explanation of the EVP_BytesToKey method (in /doc/ssleay.txt of the openssl source):

/* 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):

So based on that I was able to come up with this C# method (which seems to work for my purposes and assumes 32-byte key and 16-byte 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://开头要点.github.com / 1339719

UPDATE: Here's more/less the same implementation but uses the .NET DeriveBytes interface: https://gist.github.com/1339719