Ниже приведен код C #, который расшифровывает кодированную строку в C #.
RijndaelManaged RijndaelCipher = new RijndaelManaged(); string DecryptedData; byte[] EncryptedData = Convert.FromBase64String(TextToBeDecrypted); byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString()); //Making of the key for decryption PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt); //Creates a symmetric Rijndael decryptor object. ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16)); byte[] plainText = Decryptor.TransformFinalBlock(EncryptedData, 0, EncryptedData.Length); //Converting to string DecryptedData = Encoding.Unicode.GetString(plainText);
Но я хочу, чтобы выше того же кода в PHP. Я попробовал под кодом ниже, но это не дает мне правильный результат.
function Decrypt( $encrypted, $key, $iv ){ $encrypted=base64_decode($encrypted); return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CFB, $iv); }
Здесь я получаю вывод $)íqyZiG¤õ¡¹¡
Я передал $s = 'cJ4ZJD3Vkf3Dv5uxrWiTQg=='
и $key = '123'
(это то же самое, что используется при шифровании на C #).
Что я должен передать в $iv
чтобы получить дешифрованный вывод как « Snehal
»?
Во-первых, вам нужен режим MCRYPT_RIJNDAEL_128 не 256 и CBC. Но, большая проблема – PasswordDeriveBytes. Я не думаю, что это доступно для PHP. Но … с небольшим количеством работы, просматривающей источник MS и источник Mono, можно создать нечто подобное.
Легкий бит:
<?php $encb64 = "cJ4ZJD3Vkf3Dv5uxrWiTQg=="; $pwd = "123"; $salt = "3"; $enc = base64_decode($encb64); $decpad = Decrypt($enc, $pwd, $salt); // Remove the padding $pad = ord($decpad[($len = strlen($decpad)) - 1]); $dec = substr($decpad, 0, strlen($decpad) - $pad); echo "Enc: " . bin2hex($enc) . "\r\n"; echo "Dec: " . $dec . "\r\n"; function Decrypt($ciphertext, $password, $salt) { $key = PBKDF1($password, $salt, 100, 32); $iv = PBKDF1($password, $salt, 100, 16); // NB: Need 128 not 256 and CBC mode to be compatible return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv); }
?>
Затем, используя функцию PBKDF1 из этой записи в качестве отправной точки, и глядя на источник Mono и Microsoft, мы можем найти функцию ниже.
ПОЖАЛУЙСТА, обратите внимание на предупреждения. Это ОЧЕНЬ ПЛОХОЙ способ делать вещи по многим причинам, но достаточно показать, как добиться того, что было задано.
<?php function PBKDF1($pass, $salt, $count, $cb) { // This is very approximately the way that the Microsoft version of // PasswordDeriveBytes works. /// /// !!!WARNING!!! /// // This is a BAD function! // Irrespective of the fact that the use of PBKDF1 is not recommended anyway. // // This really should be put into a class with a constructor taking the // $pass, $salt and $count. // Then there should be a Reset() method to start from scratch each time a new pwd/salt is used. // And there should be a GetBytes(int) method to get the required info. // But for the sake of simplicity we are assuming the same pwd and salt for each call to // this function. This will not stand up to any scrutiny! static $base; static $extra; static $extracount= 0; static $hashno; static $state = 0; if ($state == 0) { $hashno = 0; $state = 1; $key = $pass . $salt; $base = sha1($key, true); for($i = 2; $i < $count; $i++) { $base = sha1($base, true); } } $result = ""; // Check if we have any bytes left over from a previous iteration. // This is the way MS appears to do it. To me it looks very badly wrong // in the line: "$result = substr($extra, $rlen, $rlen);" // I'm sure it should be more like "$result = substr($extra, $extracount, $rlen);" // Mono have provided what looks like a fixed version at // https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs // But I'm no cryptographer so I might be wrong. // But this seems to work for low values of $hashno and seems to work // with C# implementations. if ($extracount > 0) { $rlen = strlen($extra) - $extracount; if ($rlen >= $cb) { $result = substr($extra, $extracount, $cb); if ($rlen > $cb) { $extracount += $cb; } else { $extra = null; $extracount = 0; } return $result; } $result = substr($extra, $rlen, $rlen); } $current = ""; $clen = 0; $remain = $cb - strlen($result); while ($remain > $clen) { if ($hashno == 0) { $current = sha1($base, true); } else if ($hashno < 1000) { $n = sprintf("%d", $hashno); $tmp = $n . $base; $current .= sha1($tmp, true); } $hashno++; $clen = strlen($current); } // $current now holds at least as many bytes as we need $result .= substr($current, 0, $remain); // Save any left over bytes for any future requests if ($clen > $remain) { $extra = $current; $extracount = $remain; } return $result; } ?>
Проблема заключается в том, что вы используете код C #.
Для шифрования / дешифрования с помощью RindjaelManaged вы бы сделали что-то вроде этого (взято из примера MSDN):
myRijndael = new RijndaelManaged(); myRijndael.GenerateKey(); myRijndael.GenerateIV(); // Encrypt the string to an array of bytes. byte[] encrypted = EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV); // Decrypt the bytes to a string. string roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);
Вам нужно получить этот IV (вектор инициализации) GenerateIV()
создает с помощью атрибута IV
RindjaelManaged в том фрагменте кода C #, который вы указали, чтобы использовать его в своей PHP-подпрограмме. Даже если вам нужно использовать ICryptoTransform
вместо метода выше. AFAIK, нет способа получить его, когда даны только соль и ключ.