Зашифрованные Blowfish сообщения между NSIS и PHP

Для проекта, над которым я работаю, мне нужно зашифровать и расшифровать строку с помощью Blowfish совместимым образом через NSIS и PHP.

На данный момент я использую плагин Blowfish++ для NSIS и библиотеку mcrypt с PHP. Проблема в том, что я не могу заставить их обоих производить одинаковый вывод.

Начнем с плагина NSIS Blowfish++. В основном API:

; Second argument needs to be base64 encoded
; base64_encode("12345678") == "MTIzNDU2Nzg="

blowfish::encrypt "[email protected]***" "MTIzNDU2Nzg="
Pop $0 ; 0 on success, 1 on failure
Pop $1 ; encrypted message on success, error message on failure

Там нет упоминания о том, является ли это CBC, ECB, CFB и т. д., и я недостаточно знаком с Blowfish, чтобы сказать, прочитав в основном недокументированный источник. Я предполагаю, что это ECB, так как документы PHP для mcrypt говорят мне, что ECB не нуждается в IV.

Я также узнал, прочитав исходный код, что плагин Blowfish++ будет декодировать Base64 второй аргумент для шифрования (я не уверен, почему). Он также возвращает строку в кодировке Base64.

Что касается PHP, я в основном использую этот код для шифрования:

$plainText = "[email protected]***";
$cipher = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');   
$iv = '00000000';  // Show not be used anyway.
$key = "12345678";

$cipherText = "";
if (mcrypt_generic_init($cipher, $key, $iv) != -1)
{
    $cipherText = mcrypt_generic($cipher, $plainText);
    mcrypt_generic_deinit($cipher);        
}

echo base64_encode($cipherText);

Однако, если я сделаю все эти вещи, я получу следующий вывод от каждого:

NSIS: GyCyBcUE0s5gqVDshVUB8w==
PHP:  BQdlPd19zEkX5KT9tnF8Ng==

Что я делаю неправильно? Плагин NSIS не использует ECB? Если нет, то что он использует для IV?


person cdmckay    schedule 28.01.2010    source источник


Ответы (1)


Хорошо, я просмотрел этот код и воспроизвел ваши результаты. Проблема не в режиме шифрования — NSIS использует ECB. Проблема в том, что код NSIS Blowfish просто сломан на машинах с прямым порядком байтов.

Алгоритм Blowfish работает с двумя 32-битными целыми числами без знака. Для преобразования между 64-битным блоком открытого текста или зашифрованного текста и этими двумя целыми числами блок должен интерпретироваться как два целых числа с обратным порядком байтов. Плагин NSIS Blowfish вместо этого интерпретирует их в порядке байтов хоста, поэтому он не работает правильно на хостах с прямым порядком байтов (например, x86). Это означает, что он будет взаимодействовать сам с собой, но не с подлинными реализациями Blowfish (такими как mcrypt).

Я пропатчил Blowfish++, чтобы он работал правильно — измененные Blowfish::Encrypt и Blowfish::Decrypt приведены ниже, а новая версия blowfish.cppздесь, на Pastebin.

void Blowfish::Encrypt(void *Ptr,unsigned int N_Bytes)
{
    unsigned int i;
    unsigned char *Work;

    if (N_Bytes%8)
    {
            return;
    }

    Work = (unsigned char *)Ptr;

    for (i=0;i<N_Bytes;i+=8)
    {
        Word word0, word1;

        word0.byte.zero = Work[i];
        word0.byte.one = Work[i+1];
        word0.byte.two = Work[i+2];
        word0.byte.three = Work[i+3];

        word1.byte.zero = Work[i+4];
        word1.byte.one = Work[i+5];
        word1.byte.two = Work[i+6];
        word1.byte.three = Work[i+7];

        BF_En(&word0, &word1);

        Work[i] = word0.byte.zero;
        Work[i+1] = word0.byte.one;
        Work[i+2] = word0.byte.two;
        Work[i+3] = word0.byte.three;

        Work[i+4] = word1.byte.zero;
        Work[i+5] = word1.byte.one;
        Work[i+6] = word1.byte.two;
        Work[i+7] = word1.byte.three;
    }

    Work = NULL;
}

void Blowfish::Decrypt(void *Ptr, unsigned int N_Bytes)
{
    unsigned int i;
    unsigned char *Work;

    if (N_Bytes%8)
    {
            return;
    }

    Work = (unsigned char *)Ptr;
    for (i=0;i<N_Bytes;i+=8)
    {
        Word word0, word1;

        word0.byte.zero = Work[i];
        word0.byte.one = Work[i+1];
        word0.byte.two = Work[i+2];
        word0.byte.three = Work[i+3];

        word1.byte.zero = Work[i+4];
        word1.byte.one = Work[i+5];
        word1.byte.two = Work[i+6];
        word1.byte.three = Work[i+7];

        BF_De(&word0, &word1);

        Work[i] = word0.byte.zero;
        Work[i+1] = word0.byte.one;
        Work[i+2] = word0.byte.two;
        Work[i+3] = word0.byte.three;

        Work[i+4] = word1.byte.zero;
        Work[i+5] = word1.byte.one;
        Work[i+6] = word1.byte.two;
        Work[i+7] = word1.byte.three;
    }

    Work = NULL;
}
person caf    schedule 28.01.2010
comment
Спасибо, кафе... Я также размещу этот пост на сайте плагинов NSIS, чтобы уберечь других программистов от траты времени на использование сломанной версии. - person cdmckay; 28.01.2010