C# версия метода OpenSSL EVP_BytesToKey?
Я ищу прямую.NET реализацию функции OpenSSL EVP_BytesToKey. Самым близким, что я нашел, является класс http://msdn.microsoft.com/en-us/library/system.security.cryptography.passwordderivebytes.aspx (и Rfc2898DeriveBytes), но он, кажется, немного отличается и не генерирует тот же ключ и iv, что и EVP_BytesToKey.
Я также нашел эту реализацию, которая кажется хорошим началом, но не учитывает количество итераций.
Я понимаю, что есть OpenSSL.NET, но это просто оболочка вокруг нативных библиотек openssl, а не "настоящая" реализация.NET.
1 ответ
Я нашел это псевдокодовое объяснение метода EVP_BytesToKey (в /doc/ssleay.txt источника openssl):
/* 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 изменил алгоритм дайджеста, используемый в некоторых внутренних компонентах. Раньше использовался MD5, а 1.1.0 переключался на SHA256. Будьте осторожны, изменения не влияют на вас обоих EVP_BytesToKey
и такие команды, как openssl enc
,