Почему выходные данные Blowfish в Java и PHP отличаются только на 2 символа? - PullRequest
13 голосов
/ 20 июля 2011

У меня есть сценарий шифрования blowfish на PHP и JAVA, и наоборот, он работал нормально до сегодняшнего дня, когда я столкнулся с проблемой.

Один и тот же контент по-разному шифруется в Java и PHP только двумя символами, чтодействительно странно.

PHP

wTHzxfxLHdMm/JMFnoh0hciS/JADvFFg

Java

wTHzxfxLHdMm/JMFnoh0hciS/D8DvFFg
-------------------------^^

Как видите, эти две позиции не совпадают.К сожалению, это реальный адрес электронной почты, и я не могу им поделиться.Также я не смог воспроизвести проблему с другими несколькими значениями, которые я тестировал.Я пытался изменить классы кодирования Base64 на Java, и это не помогло.

Исходный код для PHP здесь , а для Java здесь .

Что я мог сделать, чтобы решить эту проблему?

Ответы [ 3 ]

7 голосов
/ 20 августа 2011

Давайте посмотрим на ваш код Java:

String c = new String(Test.encrypt((new String("thevalue")).getBytes(),
                                   (new String("mykey")).getBytes()));
...
System.out.println("Base64 encoded String:" +
                   new sun.misc.BASE64Encoder().encode(c.getBytes()));

Что вы здесь делаете:

  1. Преобразование строки открытого текста в байты, используя кодировку системы по умолчанию
  2. преобразует ключ в байты, используя системную кодировку по умолчанию
  3. шифрует байты
  4. преобразует зашифрованные байты обратно в строку , используя системную настройку по умолчаниюкодировка
  5. преобразовывает зашифрованную строку обратно в байты , используя системную кодировку по умолчанию
  6. , кодирует эти зашифрованные байты, используя Base64.

Проблеманаходится в шаге 4. Предполагается, что произвольный байтовый массив представляет строку в кодировке вашей системы по умолчанию, а обратное кодирование этой строки дает тот же байт [].Это справедливо для некоторых кодировок (например, для серии ISO-8859), но не для других.В Java, когда некоторый байт (или последовательность байтов) не может быть представлен в данной кодировке, он будет заменен другим символом, который позже для повторного преобразования будет отображен в байт 63 (ASCII ?).На самом деле, в документации даже сказано:

Поведение этого конструктора, когда указанные байты недопустимы в кодировке по умолчанию, не указано.

В вашем случае естьнет никакой причины делать это вообще - просто используйте байты, которые ваш метод encrypt выводит напрямую, чтобы преобразовать их в Base64.

byte[] encrypted = Test.encrypt("thevalue".getBytes(),
                                "mykey".getBytes());
System.out.println("Base64 encoded String:"+ new sun.misc.BASE64Encoder().encode(encrypted));

(Также обратите внимание, что я удалил лишние вызовы конструктора new String("...") здесь,хотя это не относится к вашей проблеме.)

Следует помнить: Никогда не преобразовывать произвольный байт [], который не был получен при кодировании строки, в строку. Выводалгоритма шифрования (и большинства других криптографических алгоритмов, кроме дешифрования), безусловно, относится к категории данных, которые не следует преобразовывать в строку .

и никогда не использовать кодировку по умолчанию системы, если вы хотите переносимые программы.

0 голосов
/ 12 августа 2011

Вопрос. Пробовали ли вы связанную библиотеку расшифровки PHP для расшифровки зашифрованного текста, сгенерированного PHP? Вы пробовали связанную библиотеку дешифрования JAVA, чтобы расшифровать зашифрованный текст JAVA?

Если оба выдают разные выходные данные, то один ДОЛЖЕН потерпеть неудачу при расшифровке.

Это один PHP или Java?

Какой бы это ни был - я бы попытался продублировать еще одну такую ​​ошибку с общедоступной строкой ... дать эту строку в качестве модульного теста - разработчику или разработчикам, создавшим код шифрования / дешифрования на языке, который двустороннее шифрование / дешифрование завершается неудачно.

Тогда ... подождите, пока они это исправят.

Не уверен в каких-либо более быстрых решениях - за исключением, может быть, изменения провайдеров библиотеки шифрования / дешифрования ... или прокрутки своего собственного ...

0 голосов
/ 21 июля 2011

Ваш код мне кажется правильным.

Похоже, у вас есть конечные пробелы на входе в одну из этих программ, и это только одна. Я скажу вам почему:

Каждый из этих 4-символьных блоков представляет 3 символа в зашифрованной строке. Эта другая часть (JA и D8 в 7-м блоке) на самом деле происходит от одного другого символа.

ШТФ xfxL HdMm / JMF noh0 hciS / JAD vFFg

WTHz xfxL HdMm / JMF noh0 hciS / D8D vFFg

Если я правильно понял, ваш адрес электронной почты длиной 19 символов. 20-й символ в одной из ваших строк ввода - это пробел.

...