Я потратил пару часов, пытаясь понять это, но я просто не могу заставить его работать. У меня есть процедура шифрования на C #, которую мне нужно сопоставить в php. Я не могу изменить версию C #, это не вариант (третья сторона на этом основана).
Вот код C #:
//In C# // Console.WriteLine(ApiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl")); // Results in: // XvHbR/CsLTo= public static string ApiEncode(string data, string secret) { byte[] clear; var encoding = new UTF8Encoding(); var md5 = new MD5CryptoServiceProvider(); byte[] key = md5.ComputeHash(encoding.GetBytes(secret)); TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider(); des.Key = key; des.Mode = CipherMode.ECB; des.Padding = PaddingMode.PKCS7; byte[] input = encoding.GetBytes(data); try { clear = des.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); } finally { des.Clear(); md5.Clear(); } return Convert.ToBase64String(clear); }
Вот лучшее из того, что я придумал в PHP:
//In PHP // echo apiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl"); // Results in: // 5aqvY6q1T54= function apiEncode($data, $secret) { //Generate a key from a hash $key = md5(utf8_encode($secret), true); //Create init vector $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ecb), MCRYPT_RAND); //Pad for PKCS7 $blockSize = mcrypt_get_block_size('tripledes', 'ecb'); $len = strlen($data); $pad = $blockSize - ($len % $blockSize); $data .= str_repeat(chr($pad), $pad); //Encrypt data $encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb'); //, $iv); return base64_encode($encData); }
Насколько я знаю, я правильно обрабатываю дополнение PKCS7 на стороне PHP. Я не уверен, что еще попробовать.
Одно замечание: C # происходит на окнах, а PHP на Linux – не уверен, что это должно иметь значение.
Длина заполнения в вашей версии PHP зависит от длины пароля. Это неверно. Он должен основываться на длине вашего сообщения.
Попробуйте заменить strlen($password)
на strlen($data)
.
Вторая проблема заключается в том, что mcrypt
библиотеки mcrypt
требуются 24-байтные ключи. Triple DES применяет обычный DES три раза, поэтому вы можете вызывать 8-байтовый ключ, используемый в каждом раунде DES K 1 , K 2 и K 3 . Существуют разные способы выбора этих ключей. Наиболее безопасным является выбор трех разных ключей. Другой способ – установить K 3 равным K 1 . Наименее безопасный метод (эквивалент DES) заключается в том, чтобы сделать K 1 = K 2 = K 3 .
Большинство библиотек достаточно «умны», чтобы интерпретировать 16-байтовый ключ 3DES в качестве второго варианта выше: K 3 = K 1 . Реализация .NET делает это для вас, но библиотека mcrypt
не является; вместо этого он устанавливает K 3 = 0. Вам нужно будет исправить это самостоятельно и передать mcrypt
24-байтовый ключ.
После вычисления хеша MD5 возьмите первые 8 байтов $key
и добавьте их в конец $key
, чтобы у вас было 24-байтовое значение для передачи в mcrypt_encrypt()
.
Я нашел решение, проверьте эту ссылку, может вам помочь. http://sanity-free.com/131/triple_des_between_php_and_csharp.html
И вот функция дешифрования на всякий случай:
public static string Decrypt(string cypherString) { byte[] key = Encoding.ASCII.GetBytes("icatalogDR0wSS@P6660juht"); byte[] iv = Encoding.ASCII.GetBytes("iCatalog"); byte[] data = Convert.FromBase64String(cypherString); byte[] enc = new byte[0]; TripleDES tdes = TripleDES.Create(); tdes.IV = iv; tdes.Key = key; tdes.Mode = CipherMode.CBC; tdes.Padding = PaddingMode.Zeros; ICryptoTransform ict = tdes.CreateDecryptor(); enc = ict.TransformFinalBlock(data, 0, data.Length); return UTF8Encoding.UTF8.GetString(enc, 0, enc.Length); }
Взгляните на encoding.getBytes, вам нужен секретный ключ Bytes из UTF8 …
Кажется, версия C # не устанавливает IV . Это может быть проблемой, если вы не знаете, что это такое, потому что msdn говорит:
Свойство IV автоматически устанавливается в новое случайное значение всякий раз, когда вы создаете новый экземпляр одного из классов SymmetricAlgorithm или когда вы вручную вызываете метод GenerateIV.
Это похоже на версию PHP, вы используете IV . Вы можете попробовать не поставлять IV и надеяться, что версия C # также использует нули.
Edit: Похоже на ECB, IV игнорируется.
Вам также может потребоваться кодировать ключ, как в версии C #, используя utf8-encode