Versão C # do método OpenSSL EVP_BytesToKey?

Eu estou olhando para a implementação .NET em linha reta da function OpenSSL EVP_BytesToKey . A coisa mais próxima que eu encontrei é a class System.Security.Cryptography.PasswordDeriveBytes (e Rfc2898DeriveBytes ), mas parece ser um pouco diferente e não gera a mesma chave e iv como EVP_BytesToKey.

Também encontrei essa implementação que parece ser um bom começo, mas não leva em conta a contagem de iterações.

Eu percebo que há OpenSSL.NET, mas é apenas um wrapper em torno das DLLs openssl nativas não uma implementação .NET “real”.

Eu encontrei esta explicação de pseudo-código do método EVP_BytesToKey (em /doc/ssleay.txt da fonte openssl):

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

Então, com base nisso, consegui criar esse método C # (que parece funcionar para os meus propósitos e pressupõe a chave de 32 bytes e o iv de 16 bytes):

 private static void DeriveKeyAndIV(byte[] data, byte[] salt, int count, out byte[] key, out byte[] iv) { List hashList = new List(); 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); } 

ATUALIZAÇÃO : Veja mais ou menos a mesma implementação, mas usa a interface do .NET DeriveBytes: https://gist.github.com/1339719


O OpenSSL 1.1.0c alterou o algoritmo de resumo usado em alguns componentes internos. Antigamente, o MD5 era usado e o 1.1.0 comutado para SHA256. Tenha cuidado para que a mudança não esteja afetando você em EVP_BytesToKey e comandos como o openssl enc .