2011-11-04 63 views
4

我正在尋找OpenSSL EVP_BytesToKey函數的直接.NET實現。我發現的最接近的就是System.Security.Cryptography.PasswordDeriveBytes類(Rfc2898DeriveBytes),但它似乎是slightly different並不會產生同樣的關鍵IV爲EVP_BytesToKey。C#版本的OpenSSL EVP_BytesToKey方法?

我也發現這implementation這似乎是一個好開始,但沒有考慮到迭代計數。

我意識到有OpenSSL.NET,但它只是本地openssl DLL的包裝而不是「真正的」.NET實現。

回答

12

我發現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); 
} 

UPDATE:這裏有更多/相同的實現較少,但使用的.N ET DeriveBytes接口:https://gist.github.com/1339719


OpenSSL 1.1.0c changed the digest algorithm在一些內部組件使用。以前使用MD5,1.1.0切換到SHA256。請注意,變更不會影響您在EVP_BytesToKeyopenssl enc之類的命令。