Недавно проблема возникла относительно присоединения API с платежным процессором, кто запрашивал строку быть зашифрованной, чтобы использоваться в качестве маркера, с помощью стандарта TripleDES. Наши Приложения, запущенные с помощью ColdFusion, который имеет Зашифровать тег - который поддерживает TripleDES - однако результат, который мы возвращали, не были тем, что ожидал платежный процессор.
В первую очередь, вот получающийся маркер, который ожидал платежный процессор.
AYOF+kRtg239Mnyc8QIarw==
И ниже отрывок ColdFusion, который мы использовали, и получившая строка.
<!--- Coldfusion Crypt (here be monsters) --->
<cfset theKey="123412341234123412341234">
<cfset theString = "username=test123">
<cfset strEncodedEnc = Encrypt(theString, theKey, "DESEDE", "Base64")>
<!---
resulting string(strEncodedEnc): tc/Jb7E9w+HpU2Yvn5dA7ILGmyNTQM0h
--->
Как Вы видите, это не возвращало строку, на которую мы надеялись. Ища решение, мы угробили ColdFusion для этого процесса и попытались воспроизвести маркер в PHP.
Теперь я знаю, что различные языки реализуют шифрование по-разному - например, в прошлом руководящем шифровании между приложением C# и бэкендом PHP, я должен был играть с дополнением, чтобы заставить два говорить, но мой опыт состоял в том, что PHP обычно ведет себя когда дело доходит до стандартов шифрования.
Так или иначе на источнике PHP мы попробовали, и получившая строка.
/* PHP Circus (here be Elephants) */
$theKey="123412341234123412341234";
$theString="username=test123";
$strEncodedEnc=base64_encode(mcrypt_ecb (MCRYPT_3DES, $theKey, $theString, MCRYPT_ENCRYPT));
/*
resulting string(strEncodedEnc): sfiSu4mVggia8Ysw98x0uw==
*/
Как можно явно видеть, у нас есть другая строка, которая отличается и от строки, ожидаемой платежным процессором И ОТ той, произведенной ColdFusion. Выдайте методы интеграции головы против стены.
После многих туда и сюда связь с платежным процессором (партии и много представителей, заявляющих ', мы не можем помочь с кодированием проблем, необходимо делать его неправильно, прочитать руководство'), мы наконец наращивались кому-то больше чем с несколькими клетками головного мозга для трения вместе, кто смог отступить и на самом деле посмотреть на и диагностировать проблему.
Он согласился, наш CF и попытки PHP не приводили к корректной строке. После быстрого поиска он также согласился, что это не был neccesarily наш источник, а скорее как эти два языка реализовали свое видение стандарта TripleDES.
Входя в офис этим утром, мы были встречены электронным письмом с отрывком исходного кода в Perl. Это, был код, который они непосредственно использовали на их конце для создания ожидаемого маркера.
#!/usr/bin/perl
# Perl Crypt Calamity (here be...something)
use strict;
use CGI;
use MIME::Base64;
use Crypt::TripleDES;
my $cgi = CGI->new();
my $param = $cgi->Vars();
$param->{key} = "123412341234123412341234";
$param->{string} = "username=test123";
my $des = Crypt::TripleDES->new();
my $enc = $des->encrypt3($param->{string}, $param->{key});
$enc = encode_base64($enc);
$enc =~ s/\n//gs;
# resulting string (enc): AYOF+kRtg239Mnyc8QIarw==
Так, там у нас есть он. Три языка, три реализации того, что они заключают в кавычки в документации как Шифрование Стандарта TripleDES и три полностью различных получивших строки.
Мой вопрос, на основе Вашего опыта этих трех языков и их реализаций алгоритма TripleDES, Вы смогли заставить каких-либо двух из них давать тот же ответ, и раз так какие тонкие настройки к коду необходимо было сделать для прибытия в результат?
Я понимаю, что это - очень вытянутый вопрос, но я хотел дать четкую и точную установку для каждого этапа тестирования этого, мы должны были выполнить.
Я буду также выполнять еще некоторую следственную работу над этим предметом позже и отправлю любые результаты, которые я придумываю к этому вопросу, так, чтобы другие могли избежать этой головной боли.
Никогда не следует использовать Perl's TripleDES. Он делает так много странных вещей, и вы получите удовольствие.
Ваша первая проблема в том, что ключи в Perl - шестнадцатеричные, и вам нужно преобразовать их в двоичные. Попробуйте сделать это в PHP,
$theKey="123412341234123412341234";
$key = pack('H*', str_pad($theKey, 16*3, '0'));
$strEncodedEnc=base64_encode(mcrypt_ecb (MCRYPT_3DES, $key, $theString, MCRYPT_ENCRYPT));
echo $strEncodedEnc, "\n";
В результате вы получите,
AYOF+kRtg239Mnyc8QIarw==
Затем вам придется заполнить его странным образом. Я забыл подробности. Вам повезло с этим примером (в нем 16 символов).
О, это весело!
> hex clear_text
0000 75 73 65 72 6e 61 6d 65 3d 74 65 73 74 31 32 33 username =test123
> openssl des3 -in clear_text -out crypt_text
enter des-ede3-cbc encryption password: 123412341234123412341234
Verifying - enter des-ede3-cbc encryption password: 123412341234123412341234
> hex crypt_text
0000 53 61 6c 74 65 64 5f 5f d7 1b 37 a6 e0 c4 99 d1 Salted__ ..7.....
0010 ce 39 7f 87 5e 8b e8 8a 27 ca 39 41 58 01 38 16 .9..^... '.9AX.8.
0020 a5 2b c8 14 ed da b7 d5 .+......
> base64 crypt_text
U2FsdGVkX1/XGzem4MSZ0c45f4dei+iKJ8o5QVgBOBalK8gU7dq31Q==
> openssl version
OpenSSL 0.9.8k 25 Mar 2009
> base64 --version | head -n 1
base64 (GNU coreutils) 7.1
Вам следует поговорить с экспертом по криптографии, попробуйте, возможно, списки рассылки openssl-users или dev-tech-crypto@mozilla, если здесь не появится кто-нибудь полезный.
Ответ Coldfusion:
Первая проблема заключается в том, что длина вашего ключа не подходит для Triple DES. ZZ Coder правильно понял, что он должен быть дополнен нулями до правильной длины.
Следующим шагом является преобразование ключа в шестнадцатеричный. Чтобы сделать это в CF, у нас есть:
<cfset theKey="123412341234123412341234000000000000000000000000">
<cfset encodedKey = ToBase64(BinaryDecode(theKey, "HEX"))>
Последний шаг заключается в том, что результат также не дополняется, поэтому нам нужно указать это в алгоритме шифрования в CF:
<cfset strEncodedEnc = Encrypt(theString, encodedKey, "DESEDE/ECB/NoPadding", "Base64")>
Полученный полный код:
<cfset theKey="123412341234123412341234000000000000000000000000">
<cfset encodedKey = ToBase64(BinaryDecode(theKey, "HEX"))>
<cfset theString = "username=test123">
<cfset strEncodedEnc = Encrypt(theString, encodedKey, "DESEDE/ECB/NoPadding", "Base64")>
<cfdump var="#strEncodedEnc#"><br>
results in:
AYOF+kRtg239Mnyc8QIarw==