Использование System.Security.Cryptography для шифрования текста в соответствии с OpenSSL - PullRequest
1 голос
/ 15 октября 2010

Мне нужно правильно зашифровать текст (в частности, пароль), чтобы сторонняя организация могла его расшифровать.Они предоставили мне ключ, который они используют для расшифровки, и сказали, что они будут расшифровывать его на своем конце с помощью OpenSSL.

Я пытался получить классы AESManaged и RijndaelManaged в System.Security.Криптография для создания чего-то дешифруемого, но не очень успешного.

Пример OpenSSL для шифрования, который они предоставили:

echo "пароль" |enc -base64 -aes-256-cbc -k "provideKey" -p -md sha1

Поэтому мне нужно создать CryptoStream, который является шифром AES с размером ключа 256 и режимом шифрованияCBC.А затем base64 кодирует полученный байтовый массив.Эта часть довольно прямолинейна.

То, что я не уверен, как создать, является ключом, и я ищу точку в правильном направлении.

Я заметил, что все расшифровки base64 текста, созданные этими параметрами в OpenSSL, начинаются с тех же 8 символов «Salted__».Так что я предполагаю, что именно Salt используется для генерации ключа.

Кто-нибудь знает, как создать ключ SHA1 с закрытым ключом и "Salted __"?

Я знаю оOpenSSL.Net проект, чтобы обернуть DLL OpenSSL, но я хотел бы избежать этого пути, если это возможно.

Ответы [ 2 ]

3 голосов
/ 29 октября 2010

Благодаря Точка Грегса в правильном направлении , было довольно легко скопировать генерацию Ключа и Начального вектора, которая происходила в EVP_BytesToKey () .

В основном они создают 48-байтовый массив (32-байтовый массив для ключа и 16-байтовый массив для IV) и используют SHA1 для хеширования закрытого ключа и 8 солт-байтов в этот буфер.Первый хеш - это только закрытый ключ и соль, а последующие хеши - это последний сгенерированный хеш, сцепленный с ключом и солт-байтами, до заполнения 48-байтового массива.

Ключ - это только первые 32 байта иIV - это последние 16 байтов.

Используя класс AESManaged из System.Security.Crytpography , а также ключ и IV, полученные из этого метода, я смог зашифровать свои пароли таким образом, чтобыСторонние разработчики, использующие библиотеки OpenSSL, могут расшифровать.

Вот алгоритм, который я использовал для получения ключа и начального вектора:

    /// <summary>
    /// Derives the key and IV.
    /// </summary>
    /// <param name="saltBytes">The salt bytes.</param>
    /// <param name="privateKeyBytes">The private key bytes.</param>
    /// <param name="iv">The iv.</param>
    /// <returns>The Key</returns>
    private static byte[] DeriveKeyAndIV(byte[] saltBytes, byte[] privateKeyBytes, out byte[] iv)
    {
        // we are creating a 16 byte initial vector and a 32 byte key 
        const int ivLength   = 16;
        iv = new byte[ivLength];
        const int keyLength  = 32;
        var key = new byte[keyLength];

        //SHA1 creates a 20 byte hash
        const int hashLength = 20;

        // container to store the hashed values
        var keyContainer = new byte[keyLength + ivLength];

        // munge together the privateKey and salt
        var privateKeyAndSalt = new byte[privateKeyBytes.Length + saltBytes.Length];
        Array.Copy(privateKeyBytes, privateKeyAndSalt, privateKeyBytes.Length);
        Array.Copy(saltBytes, 0, privateKeyAndSalt, privateKeyBytes.Length, saltBytes.Length);

        // use SHA1 crypto to match the -md SHA1 command line.
        var sha1 = new SHA1CryptoServiceProvider();

        // hashtarget holds the successive hash's source bytes.
        var hashtarget = new byte[hashLength + privateKeyAndSalt.Length];

        byte[] currentHash = null;
        var bytesCopied = 0;

        // do the hashing until we fill the container
        while (bytesCopied < (ivLength + keyLength))
        {
            // Hash(0) is an empty set so just concatenate private key and salt.
            if (currentHash == null)
            {
                currentHash = sha1.ComputeHash(privateKeyAndSalt);
            }
            else
            {
                // successive hashes are done on Hash(prev) + private key + salt.
                Array.Copy(currentHash, hashtarget, currentHash.Length);
                Array.Copy(privateKeyAndSalt, 0, hashtarget, currentHash.Length, privateKeyAndSalt.Length);
                currentHash = hashtarget;
                currentHash = sha1.ComputeHash(currentHash);
            }
            var copyAmount = Math.Min(currentHash.Length, keyContainer.Length - bytesCopied);
            Array.Copy(currentHash, 0, keyContainer, bytesCopied, copyAmount);
            bytesCopied += copyAmount;
        }

        // split out bytes in the container. first 32 are key, last 16 are iv.
        Array.Copy(keyContainer, 0, key, 0, key.Length);
        Array.Copy(keyContainer, key.Length, iv, 0, iv.Length);

        return key;
    }  
1 голос
/ 17 октября 2010

Я немного покопался в соответствующем исходном коде openssl (apps/enc.c), и я думаю, что openssl использует несколько проприетарный подход.Я признаю, что мне было лень выяснять все детали, но они есть.Похоже, строка ASCII «Salted__», за которой следуют 8 случайных солт-байтов, добавляются к файлу.Ключ AES и AES iv * получены из пароля и соли с использованием метода openssl с именем EVP_BytesToKey().Алгоритм описан на этой странице руководства.В enc.c исходном коде версии 1.0.0a эта часть начинается со строки 510.

Надеюсь, это поможет вам начать работу.

...