Портирование PHP-дешифрования AES-256-CBC на C # - PullRequest
0 голосов
/ 06 января 2019

У меня есть следующая подпрограмма расшифровки PHP, которая работает безупречно, и мне нужна помощь в преобразовании ее в c #. Я перепробовал много подходов, но ни один из них не работает. Мне удалось сопоставить выходные данные хэш-функции между C # и PHP. также соответствует вывод преобразования из и в base64.

PHP код:

function decrypt($encrypted_txt, $secret_key, $secret_iv)
{
$encrypt_method = "AES-256-CBC";
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
$output = openssl_decrypt(base64_decode($encrypted_txt), $encrypt_method, $key, 0, $iv);
return $output;
}
secret_key= "t-3zafRa"; 
secret_key_hash = "d03a4d94b29e7f55c80726f1152dcebc9f03f4c698470f72083af967cf786b6b";

проблема в том, что хеш ключа составляет 64 байта, что недопустимо для AES-256, но я не уверен, как он работает в php и как функция openssl_decrypt php работает с ключами.

Я также пытался передать MD5 ключевого хэша, но также не смог расшифровать.

byte[] asciiBytes = ASCIIEncoding.ASCII.GetBytes(keyhash);
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string keymd5 = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower(); //To match with PHP MD5 output

C # Функция хеширования:

static string sha256(string randomString)
        {
            var crypt = new System.Security.Cryptography.SHA256Managed();
            var hash = new System.Text.StringBuilder();
            byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
            foreach (byte theByte in crypto)
            {
                hash.Append(theByte.ToString("x2"));
            }
            return hash.ToString();
        }

C # Процедура расшифровки:

static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
        {
            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (key == null || key.Length <= 0)
                throw new ArgumentNullException("key");
            if (iv == null || iv.Length <= 0)
                throw new ArgumentNullException("iv");

            // Declare the RijndaelManaged object
            // used to decrypt the data.
            RijndaelManaged aesAlg = null;

            // Declare the string used to hold
            // the decrypted text.
            string plaintext;

            // Create a RijndaelManaged object
            // with the specified key and IV.
           aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };

            // Create a decrytor to perform the stream transform.
            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
            // Create the streams used for decryption.
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                        srDecrypt.Close();
                    }
                }
            }

            return plaintext;
        }

любая помощь или идеи высоко ценятся.

1 Ответ

0 голосов
/ 06 января 2019

openssl_decrypt просто берет столько байтов для ключа, сколько требуется для алгоритма. Поскольку ваш алгоритм «AES-256-CBC» использует 32 байта (256 бит), а AES-256 определяется как AES с 256-битным ключом (и 14 раундами, а не 10 или 12).

Способ, которым PHP делает это, заключается в добавлении 00 значащих байтов справа в случае, если ключ слишком мал, или - как в вашем случае - просто в игнорировании байтов после 32-го. Это не очень хороший способ поведения любой криптографической библиотеки, особенно для языков высокого уровня, таких как PHP, но библиотека оболочки OpenSSL делает это в любом случае.

Таким образом, вы должны извлечь первые 32 байта из шестнадцатеричного ключа и использовать его в качестве ключа в C # для совместимости. Использование разных хеш-функций, конечно, не сработает, MD5 и SHA-256 полностью несовместимы (по замыслу). Конечно, теперь у вас осталось 16 байт в шестнадцатеричном коде, что означает, что вы используете AES-256 с 128-битными ключами, что дает вам 128-битную безопасность. И да, вам нужно использовать заполнение PKCS # 7 в C #.


Обратите внимание, что использование CBC со статическим IV небезопасно. Использование режима CBC для безопасности в транспортном режиме небезопасно. Использование SHA-256 или любого обычного хеширования над паролем или ключом с небольшой энтропией небезопасно. Хранение ключей в строках обычно небезопасно.

Работать с крипто достаточно сложно; обеспечить его безопасность намного сложнее и требует понимания, какого черта вы делаете в первую очередь. Вам нужно начать с хорошего протокола для вашего конкретного случая использования (и это уже пропускает несколько шагов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...