Расшифровать строку в C# зашифрованную в PHP (Blowfish)


Я изо всех сил пытаюсь расшифровать некоторые значения в C#, которые зашифрованы в PHP. Шифрование в PHP si осуществляется с помощью следующего:

function encrypt($pure_string, $encryption_key) {
  $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  $iv = 'fÔdñá1f¦';
  $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
  $encrypted_string = base64_encode($encrypted_string);
  return $encrypted_string;
}

Поскольку используется режим ЕЦБ IV, вероятно, он не используется, но все равно это не помогает. Самая большая проблема заключается в том, что документация PHP настолько плоха, и она не указывает, какую кодировку используют функции! Передаваемая строка имеет различные значения байтов в зависимости от кодировки, и в конечном итоге шифрование (в данном случае Blowfish) имеет дело с байты.

Не зная кодировки, я просто пробую разные кодировки в своем коде C#, но безуспешно. Где-то я читал, что PHP использует внутреннюю кодировку "iso-8859-1", но даже с этим он не работает.

Удалось ли кому-нибудь расшифровать в C# некоторое значение, которое было зашифровано в PHP с помощью глупой функции mcrypt_encrypt()?

Обновить

Я сделал пример на PHP. Код:

define("ENCRYPTION_KEY", "1234asdf");
define("IV", "1#^ÊÁñÔ0");

$clearText = "abc";

function encrypt($pure_string, $encryption_key, $iv) {
  $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
  $encrypted_string = base64_encode($encrypted_string);
  return $encrypted_string;
}

$encrypted_string = encrypt($clearText, ENCRYPTION_KEY, IV);

echo "Key:" . ENCRYPTION_KEY . "<br />";
echo "IV:" . IV . "<br />";
echo "Clear Text:" . $clearText . "<br />";
echo "Encrypted Text:" . $encrypted_string . "<br />";

И в результате получается:

Key:1234asdf
IV:1#^ÊÁñÔ0
Clear Text:abc
Encrypted Text:OiZ6QIdhXYk=

Также Я подтверждено, что IV не используется, любое значение я передаю результат тот же.

2 2

2 ответа:

Ну, проблема в вашем случае - это не часть расшифровки blowfish в c#, это часть шифрования в php. И нет, это не об использовании mcrypt_encrypt, это ошибка, чтобы вызвать utf8_encode на уже кодированной строке utf8...

Функция расшифровки, которую я создал, использует BouncyCastle. Есть две зашифрованные строки, первая была создана с помощью функции php, которую вы опубликовали, для второй я удалил вызов utf8_encode внутри mbcrypt_encrypt.

В первом примере используется (bad) php_utf8_encoded string, нам нужно преобразовать расшифрованный массив байтов назад и вперед, чтобы получить правильный результат.

Отладьте второй вызов функции расшифровки c# и посмотрите на результат первого str1, произведенного Encoding.UTF8.GetBytes. Это правильно, без обратного и обратного преобразования кодировки.
public static string BlowfishDecrypt(string encrypted, string key)
{
    var cipher = new BufferedBlockCipher(new BlowfishEngine());
    var k = new KeyParameter(Encoding.UTF8.GetBytes(key));
    cipher.Init(false, k);

    var input = Convert.FromBase64String(encrypted);
    var length = cipher.GetOutputSize(input.Length);
    var block = new byte[length];
    var len = cipher.ProcessBytes(input, 0, input.Length, block, 0);
    var output = cipher.DoFinal(block, len);

    // dont know how we get the real length of the content here... but this will do it. But I am sure there is a better way...
    var idx = Array.IndexOf(block, (byte)0);
    var str1 = Encoding.UTF8.GetString(block, 0, idx);
    var raw1 = Encoding.GetEncoding("iso-8859-1").GetBytes(str1);
    var str2 = Encoding.UTF8.GetString(raw1);

    return str2;
}

static string original = "@€~>|";
static string encrypted_with_utf8_encode = "7+XyF+QGcA8lz5AQlLf1FA==";
static string encrypted_without = "3oWsAOEF+Kc=";
static string key = "t0ps3cr3t";

public static void Main()
{
    var decrypted1 = BlowfishDecrypt(encrypted_with_utf8_encode, key);
    var decrypted2 = BlowfishDecrypt(encrypted_without, key);
    var same = original.Equals(decrypted1);
    Debugger.Break();
}

В конце концов смог это сделать. Несколько указателей:

  • Некоторые библиотеки Blowfish в C#, похоже, имеют плохую реализацию. Тот, который работал правильно, был https://github.com/b1thunt3r/blowfish-csharp

  • Никогда не используйте методы, которые непосредственно работают со строками. Это глупо в первую очередь предлагать в любой библиотеке (даже та, что выше, имеет перегрузки, которые работают со строками, и она "предполагает", что строки находятся в Unicode!)

  • Когда имеешь дело с различные платформы, попробуйте убедить другую сторону использовать кодировку base64.

В конце концов, я удивляюсь, почему так много разработчиков (даже те, кто разрабатывает криптобиблиотеки) не понимают, что работа со строками без указания кодировки глупа и не имеет никакого смысла!