Генерация подключа шифрования Blowfish

Хорошо, поэтому я делаю небольшую реализацию иглобрюха на PHP в качестве упражнения по программированию для себя и для того, чтобы лучше узнать этот метод шифрования. Я пришел к набору работающих функций, в которых я могу шифровать данные и снова расшифровывать их, но тестовые векторы, которые я обнаружил, не согласуются с моими зашифрованными значениями... Поскольку кодирование/декодирование, кажется, работает, я предполагаю, что ошибка заключается в настройке моей функции применения секретного ключа к массиву P и S-блоки, получая другой набор значений P и значений S-блоков, поэтому закодированные значения отличаются. Может ли кто-нибудь найти, где моя логика идет наперекосяк?

Для тестового примера ключа 0x0000000000000000 и ввода текста 0x00000000000000000 первым шагом является XOR ключа с массивом P, но с ключом, состоящим из всех нулей, что приведет к тому, что массив P останется неизменным, поэтому все равно иметь шестнадцатеричные значения числа пи, с которых оно начинается. Затем 64-байтовая текстовая строка (0x0000000000000000) кодируется с использованием текущего массива P и S-блоков, и результат разделяется, чтобы заменить P1 и P2. Затем этот же вывод снова кодируется (с использованием новых значений P1 и P2), чтобы получить другой вывод, который используется для замены P3 и P4. Это продолжается до тех пор, пока не будут изменены все значения P и S-блоки. Выполняя этот процесс, я получаю следующее (исходные значения слева, значение после распространения через процесс секретного ключа справа):

P1: 243f6a88 ⇒ 99f2ff37
P2: 85a308d3 ⇒ 9ce5cb96
P3: 13198a2e ⇒ d8bf7d9a
P4: 03707344 ⇒ eba1db37
P5: a4093822 ⇒ 5954010a
P6: 299f31d0 ⇒ 2b121658
P7: 082efa98 ⇒ e7a5b7ed
P8: ec4e6c89 ⇒ 21a6717f
P9: 452821e6 ⇒ b2bb1bf8
P10: 38d01377 ⇒ 937f0244
P11: be5466cf ⇒ e111a3da
P12: 34e90c6c ⇒ 67170ab6
P13: c0ac29b7 ⇒ 5d1db61b
P14: c97c50dd ⇒ cdf63d96
P15: 3f84d5b5 ⇒ c4935141
P16: b5470917 ⇒ ad859868
P17: 9216d5d9 ⇒ 0ca32381
P18: 8979fb1b ⇒ 50964a67
S1,0: d1310ba6 ⇒ a96eceb6
S1,1: 98dfb5ac ⇒ 3480051c
S1,2: 2ffd72db ⇒ 8d315fa7
S1,3: d01adfb7 ⇒ 936c585a
S1,4: b8e1afed ⇒ cd9cd593
...
S4,251: c208e69f ⇒ cc091e06
S4,252: b74e6132 ⇒ 2e7b8ad3
S4,253: ce77e25b ⇒ dc3d8ec5
S4,254: 578fdfe3 ⇒ c52e90ab
S4,255: 3ac372e6 ⇒ e1866c06

Когда я кодирую 0x0000000000000000 с этим набором данных, я получаю 0x3b8a9fa06e840430, но тестовый пример говорит, что я должен получить 0x4ef997456198dd78.

Вы видите, где я иду наперекосяк?

ИЗМЕНИТЬ; Подробное шифрование после устранения проблемы с 32-битными целыми числами Вот как я интерпретирую (и я думаю, что моя программа интерпретирует) способ, которым происходит шифрование Blowfish. Имея массив P и набор S-блоков, инициализированных шестнадцатеричными значениями pi, и массив P, объединенный XOR с нулевым ключом (так что он все тот же), я делаю следующее:

Вход 0x0000000000000000 разделяется на две части, левая половина становится L0, а правая половина становится R0:

L0 = 0x00000000
R0 = 0x00000000

R1 = L0 ^ P1 = 0x00000000 ^ 0x243f6a88 = 0x243f6a88
L1 = F(R1) ^ R0 = F(0x243f6a88) ^ 0x00000000 = 0xdb2f9c4e ^ 0x00000000 = 0xdb2f9c4e

R2 = L1 ^ P2 = 0xdb2f9c4e ^ 0x85a308d3 = 0x5e8c949d
L2 = F(R2) ^ R1 = F(0x5e8c949d) ^ 0x243f6a88 = 0x33002cc0 ^ 0x243f6a88 = 0x173f4648

R3 = L2 ^ P3 = 0x173f4648 ^ 0x13198a2e = 0x426cc66
L3 = F(R3) ^ R2 = F(0x426cc66) ^ 0x5e8c949d = 0xd8a68913 ^ 0x5e8c949d = 0x862a1d8e
....

R16 = L15 ^ P16 = 0xf5e1fd40 ^ 0xb5470917 = 0x40a6f457
L16 = F(R16) ^ R15 = F(0x40a6f457) ^ 0xea27e3cc = 0x66509b85 ^ 0xea27e3cc = 0x8c777849

Now untwist and apply final P values
R_final = L16 ^ P17 = 0x8c777849 ^ 0x9216d5d9 = 0x1e61ad90
L_final = R16 ^ P18 = 0x40a6f457 ^ 0x8979fb1b = 0xc9df0f4c

Final ciphered output: 0xc9df0f4c1e61ad90, should be 0x706d9fcc1792d23a...

person MidnightLightning    schedule 31.08.2009    source источник
comment
Учитываете ли вы порядок битов? (т.е. с прямым порядком байтов для архитектуры Intel)   -  person DmitryK    schedule 01.09.2009
comment
Если вы не знали, эталонные реализации, которые могут пролить свет, доступны по адресу schneier.com/blowfish. -download.html   -  person DarkSquid    schedule 01.09.2009
comment
Я отредактировал свой ответ в ответ на ваше обновление.   -  person caf    schedule 02.09.2009
comment
Большое спасибо за помощь, кафе!   -  person MidnightLightning    schedule 03.09.2009
comment
Хорошо, я сделал еще одно дополнение. Кстати, вы должны стараться не удалять части вашего вопроса после того, как они будут решены - часть ценности SO заключается в том, что кто-то другой с той же проблемой может найти здесь решение, не спрашивая снова, и удалив части вопрос, как только на них ответили, побеждает это немного.   -  person caf    schedule 04.09.2009


Ответы (1)


Что-то не так с вашей функцией шифрования. Это должны быть результаты инициализации P-массива с нулевым ключом (мой массив P основан на нуле, но это не должно иметь значения):

P0: 243f6a88 => 706d9fcc
P1: 85a308d3 => 1792d23a
P2: 13198a2e => 2db9d714
P3: 03707344 => 966e1439
P4: a4093822 => ac21a76d
P5: 299f31d0 => 8324e988
P6: 082efa98 => ac0dc9dd
P7: ec4e6c89 => 2c38f6b3
P8: 452821e6 => 70619520
P9: 38d01377 => fa23ecbe
P10: be5466cf => 17b2f676
P11: 34e90c6c => eba13a04
P12: c0ac29b7 => 8b949e61
P13: c97c50dd => 7a147caf
P14: 3f84d5b5 => 56ccc6b6
P15: b5470917 => 4461b24d
P16: 9216d5d9 => 7361e6a1
P17: 8979fb1b => 196a7c43

Если вам нужна помощь в отслеживании ошибки, вам придется опубликовать, как продвигается алгоритм, когда он проходит этапы первого шага шифрования в инициализации, где нулевой блок шифруется с помощью начальных блоков P и S.

Дополнение 1:

Ваш расчет идет наперекосяк в F(0x5e8c949d) - это должно быть 0x33002cc0. Однако ваш первый F() верен, поэтому я предполагаю, что проблема возникает, когда ваши дополнения в функции F() переполняются вместо правильного переноса. Этот вопрос касается целочисленного переполнения PHP и имеет решение в принятом ответе, которое должно работать для вы (и на самом деле расчет, который он делает, точно такой же, как функция Blowfish F(), что я предполагаю не случайно;)

Вот как должны проходить первые два вычисления F():

F(0x243f6a88) =
        byte0 = 0x24, S0(byte0) = 0xe65525f3
        byte1 = 0x3f, S1(byte1) = 0x183eb331
        byte2 = 0x6a, S2(byte2) = 0x647d0862
        byte3 = 0x88, S3(byte3) = 0x4040cb08
((0xe65525f3 + 0x183eb331) ^ 0x647d0862) + 0x4040cb08
 = 0xdb2f9c4e
F(0x5e8c949d) =
        byte0 = 0x5e, S0(byte0) = 0x7d84a5c3
        byte1 = 0x8c, S1(byte1) = 0xeecea50f
        byte2 = 0x94, S2(byte2) = 0x1a6b1018
        byte3 = 0x9d, S3(byte3) = 0xbcc7d1f6
((0x7d84a5c3 + 0xeecea50f) ^ 0x1a6b1018) + 0xbcc7d1f6
 = 0x33002cc0

Приложение 2:

В вашей реализации F() все еще что-то не так - вот как должен работать этот третий вызов:

F(0x0426cc66) =
        byte0 = 0x04, S0(byte0) = 0xb8e1afed
        byte1 = 0x26, S1(byte1) = 0x8e7d44ec
        byte2 = 0xcc, S2(byte2) = 0x1ab93d1d
        byte3 = 0x66, S3(byte3) = 0x5121ce64
((0xb8e1afed + 0x8e7d44ec) ^ 0x1ab93d1d) + 0x5121ce64
 = 0xaf099828
person caf    schedule 01.09.2009
comment
Спасибо, было полезно посмотреть, к каким целевым значениям я должен прийти для шифрования инициализации. Я отредактировал свой вопрос, чтобы показать, что у меня сейчас есть для процесса шифрования. - person MidnightLightning; 01.09.2009
comment
Да, я использовал функцию dechex, чтобы преобразовать результат сложения обратно в шестнадцатеричный, что не срабатывало для больших чисел. Теперь я получаю правильный результат для F(0x5e8c949d), но у меня другой, неправильный результат для общего шифрования... Поэтому я подозреваю, что либо все еще что-то не так с моей функцией F, либо я зацикливаю неправильное количество раз через цикл блока, но я все еще не могу найти ошибку. Не могли бы вы еще раз взглянуть на мое обновленное шифрование? - person MidnightLightning; 03.09.2009
comment
Успех! Моя последняя ошибка заключалась в том, что моя функция обработки F-функции отбрасывала начальный ноль из входной шестнадцатеричной строки. Я рад, что третий цикл выявил эту проблему с нулевым блоком, а не где-то позже в 16 раундах. Спасибо за вашу помощь! - person MidnightLightning; 04.09.2009