Frage

Vor kurzem wurde ein Problem ergab sich in Bezug auf Einhaken eine API mit einem Zahlungsprozessor auf, die einen String wurden anfordernden verschlüsselt werden als Zeichen verwendet werden soll, unter Verwendung der TripleDES Standard. Unsere Anwendungen laufen mit Coldfusion, die einen Encrypt-Tag hat -, dass die Stützen TripleDES - aber das Ergebnis, das wir waren immer wieder war nicht das, was die Zahlung Prozessor erwartet.

Zunächst einmal ist hier die resultierende Token der Zahlungsprozessor erwartet hatten.

AYOF+kRtg239Mnyc8QIarw==

Und unten ist das Snippet von Coldfusion wir verwendet haben, und die resultierenden String zurück.

<!--- 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
--->

Wie Sie sehen können, das die Zeichenfolge nicht zurückkehrte wir uns erhofft hatten. Ich suche eine Lösung, ditched wir Coldfusion für diesen Prozess und versuchen, das Token in PHP zu reproduzieren.

Jetzt bin ich mir bewusst, dass verschiedene Sprachen Verschlüsselung auf unterschiedliche Weise implementieren - zum Beispiel in der Vergangenheit Verwaltung Verschlüsselung zwischen einer C # Anwendung und PHP-Backend habe ich habe etwa mit Polsterung zu spielen, um die beide zu erhalten, Vortrag, aber meine Erfahrung ist, dass das Verhalten von PHP im allgemeinen, wenn es um Verschlüsselungsstandards kommt.

Wie auch immer, auf die PHP-Quelle, die wir versuchen, und die resultierenden String zurück.

/* 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==
*/

Wie Sie deutlich sehen können, haben wir eine andere Zeichenfolge, die unterscheidet sich von sowohl der Zeichenfolge erwartet bekam durch den Zahlungsprozessor und den von Coldfusion erzeugt. Cue Kopf-gegen-Wand Integrationstechniken.

Nach vielen Hin-und-Her-Kommunikation mit dem Zahlungsprozessor (viele, viele Wiederholungen besagt ‚wir nicht Hilfe bei der Codierung Fragen können Sie es falsch sein muss tun, lesen Sie das Handbuch‘) wurden wir endlich jemand eskaliert mit mehr als ein paar Gehirnzellen miteinander reiben, der Schritt zurück konnte und tatsächlich aussehen zu und das Problem zu diagnostizieren.

Er stimmte zu, unsere CF und PHP Versuche wurden resultierenden nicht in der richtigen Zeichenfolge. Nach kurzer Suche, stimmte er auch, dass es nicht neccesarily unsere Quelle war, sondern vielmehr, wie die beiden Sprachen implementiert ihre Vision des TripleDES Standard.

kommend in das Büro heute Morgen wurden wir von einer E-Mail mit einem Ausschnitt des Quellcodes in Perl erfüllt. Dies ist der Code war sie an ihrem Ende direkt mit dem erwarteten Token zu erzeugen.

#!/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==

So, da haben wir es. Drei Sprachen, drei Implementierungen von dem, was sie zitieren in der Dokumentation als TripleDES Standard-Verschlüsselung, und drei völlig unterschiedliche resultierende Strings.

Meine Frage ist, aus Ihrer Erfahrung dieser drei Sprachen und ihre Implementierungen der TripleDES Algorithmus, haben Sie in der Lage gewesen, eine zwei von ihnen bekommen die gleiche Antwort zu geben, und wenn ja, welche kleine Änderungen an dem Code haben Sie müssen machen, um zu dem Ergebnis zu kommen?

Ich verstehe, das ist eine sehr herausgezogen Frage, aber ich wollte für jede Stufe klare und präzise Einstellung geben, zu testen, dass wir durchführen mussten.

Ich werde auch später noch mehr Ermittlungsarbeit zu diesem Thema durchführen, und werde alle Erkenntnisse veröffentlicht, dass ich mit dieser Frage kommen, so dass andere diese Kopfschmerzen vermeiden können.

War es hilfreich?

Lösung

Die TripleDES Perl sollte niemals verwendet werden. Es tut so viele seltsame Dinge, und Sie werden Spaß haben.

Ihr erstes Problem besteht darin, dass die Schlüssel in Perl sind hex und Sie müssen sie in binäre konvertieren. Versuchen Sie, diese in 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";

Das Ergebnis ist,

AYOF+kRtg239Mnyc8QIarw==

Dann haben Sie Pad es in einer seltsamen Art und Weise. Ich habe vergessen, die Details. Sie haben Glück mit dieser Probe (es ist 16 Zeichen).

Andere Tipps

Die Coldfusion Antwort:

Das erste Problem ist, dass Ihre Schlüssellänge für Triple DES ist nicht korrekt. ZZ Coder richtig abgeleitet, dass es auf die richtige Länge mit 0'en aufgefüllt werden muss.

Der nächste Schritt besteht darin, dass der Schlüssel zum hex konvertiert werden muss. Um dies zu tun in CF, haben wir:

<cfset theKey="123412341234123412341234000000000000000000000000">
<cfset encodedKey = ToBase64(BinaryDecode(theKey, "HEX"))>

Der letzte Schritt besteht darin, dass das Ergebnis gepolstert ist auch nicht zu werden, so müssen wir dies in dem Verschlüsselungsalgorithmus in CF angeben:

<cfset strEncodedEnc = Encrypt(theString, encodedKey, "DESEDE/ECB/NoPadding", "Base64")>

Der resultierende vollständige Code:

<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>

Ergebnisse in:

AYOF+kRtg239Mnyc8QIarw==

Ich werde den Code für jedermann enthält, die auf CCBill Upgrade zu arbeiten passiert (was klingt wie das Unternehmen in der ursprünglichen Post bezeichnet). Die PHP-Funktionen unten wird die Ausgabe von CCBill 3DES / TripleDES interne Verschlüsselung übereinstimmen, wie hier in der Dokumentation beschrieben: http://www.ccbill.com/cs/manuals/CCBill_Subscription_Upgrade_Users_Guide.pdf

//Encrypt String using 3DES Key
function encrypt($str,$key){
    $hex_key = hexmod($key);
    $bin_hex_key = pack('H*', str_pad($hex_key, 16*3, '0'));
    //Pad string length to exact multiple of 8
    $str = $str. str_repeat(' ',8-(strlen($str)%8) );   
    $out = base64_encode( mcrypt_ecb(MCRYPT_3DES, $bin_hex_key, $str, MCRYPT_ENCRYPT) );
    //print_r('Key/Hex/Str: '.$key.' -> '.$hex_key.' -> '.$str.' -> '.$out,1);
    return $out;
}

//Hex Modulus: Converts G-Z/g-z to 0-f (See @Jinyo's Post)
//Necessary to match CCBill's Encryption
function hexmod($str){
    //Convert G-Z & g-z to 0-f
    $ascii_in  = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $ascii_out = '0123456789ABCDEF0123456789ABCDEF0123abcdef0123456789abcdef0123';
    $hex_out = str_replace(str_split($ascii_in),str_split($ascii_out),$str);
    return $hex_out;
}

$triple_des_key = 'ABCDEFGHIJKLMNOPQRSTUVWX'; // <!-- 24char 3DES Key
$username_string = 'username=<username here>'; // Encrypt this string
$encrypted_username = encrypt($username_string,$triple_des_key); // <-- Output

Oh, das macht Spaß!

> 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

Sie sollten zu einem Krypto-Experten sprechen, versuchen Sie vielleicht die Mailinglisten OpenSSL-Benutzer oder Entwickler-Tech-Crypto @ mozilla, es sei denn jemand nützlich zeigt sich hier ein.

ZZ Coder war es fast. Es gibt nur noch ein paar Einschränkungen, warum die Perl und PHP-Codes zurückgegeben verschiedene Verschlüsselungen.

Zum einen, wenn es ungültig hex Buchstaben (Buchstaben nach F), ersetzen Sie sie nach folgender Regel:

  • G> 0
  • H> 1
  • I-> 2
  • J-> 3
  • ...
  • P> 9
  • Q-> A
  • R-> B
  • ...
  • V> F
  • W-> 0
  • ...
  • Z> 3

Mit dieser Methode ist der Schlüssel für AZ98AZ98AZ98AZ98AZ98AZ98 A398A398A398A398A398A398000000000000000000000000 ist (nach dem Auffüllen mit Nullen).

Zweitens ist der Text verschlüsselt werden sollten mit Leerzeichen aufgefüllt werden, so dass die Anzahl der Zeichen, die von 8. In diesem Beispiel teilbar ist, username = test123 ist durch 8 teilbar, so dass es nicht gepolstert sein muss. Aber, wenn es username = test12, dann muss es ein Leerzeichen am Ende.

Der folgende PHP-Code gibt eine Verschlüsselung, die die Perl entspricht Verschlüsselung

$theKey="A398A398A398A398A398A398000000000000000000000000";
 $key = pack("H*", $theKey);
$input = "username=test123";

$strEncodedEnc=mcrypt_ecb (MCRYPT_3DES, $key, $input, MCRYPT_ENCRYPT);
$strEncodedEnc64=base64_encode($strEncodedEnc);
echo $strEncodedEnc . "<br />";
echo $strEncodedEnc64 . "<br />";

Hat mich die meisten einen Abend, aber das ist, wie @Eric Kigathi Lösung sieht in Ruby

def encoding(key, val)
  require "openssl"
  des = OpenSSL::Cipher::Cipher.new('des-ede3')
  des.encrypt
  des.key = convert_key_to_hex_bin key

  #ENCRYPTION
  des.padding = 0 #Tell Openssl not to pad
  val += " " until val.bytesize % 8 == 0 #Pad with zeros
  edata = des.update(val) + des.final 
  b64data = Base64.encode64(edata).gsub(/\n/,'')
end

def convert_key_to_hex_bin(str)
  decoder_ring = Hash['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/'.split(//).zip('0123456789ABCDEF0123456789ABCDEF0123ABCDEF0123456789ABCDEF012345'.split(//))]
  str.gsub!(/./, decoder_ring)
  [str.ljust(16*3, '0')].pack("H*")
end

Do vorsichtig sein, wenn. Ich bin mir nicht ganz sicher, was die + und / convert am Ende. Ich vermuten, bei 4 und 5, aber ich kann Ihnen nicht sagen, ob das stimmt.

Hutspitze zu http: // opensourcetester. co.uk/2012/11/29/zeros-padding-3des-ruby-openssl/ der Verschlüsselungscode und Kommentar.

Die Coldfusion-Antwort fehlt den CCBill Schlüssel zur Arbeit modifiziert (wie in Erics Antwort) ... Ich habe Erics Antwort Lucee-Code geändert. Es sollte nicht viel Arbeit nehmen sie zurück zu ACF kompatiblen Code zu übernehmen (die Struktur in ReplaceNoCase mit einzelner ändern).

public function ccbillupgrade(string key = "XXXXXXXXXXXXXXXXXXXXXXXX", string username){

    var remote_user = padUserName("username=#arguments.username#");
    var padded_key = 
        Ucase(
            Replace(
                LJustify(
                    hexmod(arguments.key)
                , 48), // Pad key to 48 bytes (hex) 
                " ", '0', 'all'
            )
        );

    var encodedKey = ToBase64(BinaryDecode(padded_key, "HEX"));

    return Encrypt(remote_user, encodedKey, "DESEDE/ECB/NoPadding", "Base64");
}

private string function hexmod(string input) {
    return ReplaceNoCase( arguments.input,
        {
            'G' = '0', 'H' = '1',
            'I' = '2', 'J' = '3',
            'K' = '4', 'L' = '5',
            'M' = '6', 'N' = '7',
            'O' = '8', 'P' = '9',
            'Q' = 'A', 'R' = 'B',
            'S' = 'C', 'T' = 'D',
            'U' = 'E', 'V' = 'F',
            'W' = '0', 'X' = '1',
            'Y' = '2', 'Z' = '3'

        }
    );
}
private string function padUserName(string username) {
    var neededLength = Len(arguments.username) + ( 8 - Len(username) % 8 );
    return LJustify(arguments.username, neededLength);
}

Es gibt zwei Probleme (oder nicht) mit Crypt :: TripleDES:

  1. Die Tatsache, dass die Schlüssel für Crypt :: TripleDES HEX sind (früher erklärt von ZZ Coder). Sie können Ihren Schlüssel entweder durch Verwendung auspacken oder mit ord / sprintf oder einer Reihe von anderen Methoden hex:

    • $ paßt = auspacken ( "H *", "Ihr Passwort"); # Pack / auspacken Version

    • $ pass = join ( '', Karte {sprintf ( "% x", $ )} Karte {ord ($ )} split (// "PASS") );

    Crypt :: TripleDES Pads die Passphrase mit Leerzeichen (was für mich in Ordnung war)

  2. Crypt :: TripleDES tut Leerzeichen nur der Klartext-Polsterung. Es gibt zahlreiche Methoden, die Polsterung auf Java oder PHP mcrypt_encrypt verwendet werden:

    • (dh PKCS5, PKCS7, CMS.) - Unterlage mit Bytes aus dem gleichen Wert, der die Anzahl von Bytes gepolsterter zB: "andrei" -> hex: 61 6e 64 72 65 69 -> gepolsterten: 61 6e 64 72 65 69 02 02
    • Pad mit null Zeichen Beispiel: 64 72 61 6e 65 69 00 00
    • Pad mit Leerzeichen (Crypt :: TripleDES tut dies bereits)
    • Pad mit Nullen (Null-Zeichen) mit Ausnahme des letzten Byte, das die Anzahl des Bytes gepolsterten zB sein: 6e 64 72 61 65 69 00 02
    • Pad mit 0x80 gefolgt von null Zeichen Beispiel: 64 72 61 6e 65 69 80 00

Achten Sie auf Ihren Chiffre-Text, wenn sie paßt, bis irgendwann, aber das Ende ist anders dann haben Sie ein Nur-Text-padding Problem. Andernfalls könnten Sie eine Passphrase Problem haben, ein Cipher Block-Modus Problem (EBC, CBC, ..) http://www.tools4noobs.com/online_tools/encrypt/help_modes.php oder ein Algorithmus Problem.

Also, was ich in Perl tat der Lage sein, den Chiffretext von Java (die verwendet null Zeichen padding) entsprechen:

my $pass = unpack("H*", "MY PASS");
my $text = "bla bla bla";
my $pad = 8 - (length $text % 8);
$pad = 0 if ( $pad > 7 );
$text .= chr(00) x $pad;

my $des = new Crypt::TripleDES;
my $cipher = $des->encrypt3( $text, $pass );

Hope, das hilft

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top