Perl / PHP / ColdFusion içinde TripleDESgereken

6 Cevap php

Son zamanlarda bir sorun TripleDESgereken standardını kullanarak, bir belirteç olarak kullanılmak üzere şifreli bir dize talep edildi ödeme işlemci ile bir API çengel ile ilgili ortaya çıktı. Bizim Başvurular kakmak etiketi ColdFusion kullanılarak çalıştırılması - TripleDESGiriş desteklediğini - biz geri elde edemiyorlardı sonuç ödeme işlemci beklediğim değildi ancak.

Her şeyden önce, burada ödeme işlemci bekliyorduk çıkan token.

AYOF+kRtg239Mnyc8QIarw==

Ve aşağıda kullandığımız ColdFusion pasajı ve sonuçta dizedir.

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

Gördüğünüz gibi, bu bizim için umut vardı dize dönen değildi. Bir çözüm arayan, bu süreç için ColdFusion hendeğe ve PHP belirteci yeniden çalıştı.

Şimdi çeşitli dillerde farklı şekillerde şifreleme uygulamak farkında değilim - örneğin bir C # uygulama ve PHP arka uç arasındaki geçmiş yönetiminde şifreleme, ben iki konuşmak almak için dolgu ile ilgili oynamak zorunda kaldı, ama var benim deneyim şifreleme standartlarına geldiğinde PHP genellikle davrandığını olmuştur.

Neyse, biz denedik PHP kaynağı ve elde edilen dize üzerinde.

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

Size açıkça görebileceğiniz gibi, biz ödeme işlemcisi tarafından beklenen dize VE ColdFusion tarafından üretilen bir iki farklı başka bir dize var. Cue kafa karşı duvara entegrasyon teknikleri.

Ödeme işlemci (çok ve 'biz, sorunları kodlama, yanlış yapıyor olması gerekir yardım kılavuzu okuyamıyorum' belirten tekrar sürü) nihayet daha fazla olan birine tırmandı edildi ile birçok ileri-geri iletişim Sonrası geri adım başardı ve aslında bakmak ve sorunu teşhis birlikte ovmak beyin hücrelerinin bir çift.

O bizim CF ve PHP girişimleri doğru dize sonuçlanan değil, kabul etti. Hızlı bir aramadan sonra, o da neccesarily bizim kaynak olmadığını kabul etti, ama yerine iki dil TripleDESgereken standardın kendi vizyonunu hayata nasıl.

Bu sabah ofise geliyor, biz Perl, kaynak kod parçası ile bir e-posta ile karşılandı. Bu doğrudan beklenen belirteci üretmek için kendi ucunda kullandığınız kod oldu edilir.

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

Yani, biz var. Üç dil, onlar TripleDESgereken Standart Şifreleme gibi belgelerde alıntı ne üç uygulamaları ve üç tamamen farklı sonuçta elde edilen dizeler.

Benim sorum bu üç dil ve TripleDESgereken algoritma kendi uygulamalarında sizin deneyim, size aynı cevabı vermek için bunlardan herhangi ikisini almak mümkün olmuştur ve bu yüzden ne kodu tweaks sırayla yapmak zorunda olmasaydı Sonuç gelmek için?

Bu çok süzgün bir soru anlıyorum, ama biz gerçekleştirmek zorunda test her aşaması için net ve kesin bir ayar vermek istedim.

Ben de daha sonra bu konuda biraz daha soruşturma işi yapan olacak, ve diğerleri bu baş ağrısı önlemek böylece, ben bu soruya ile gelip herhangi bir bulgu yayınlayacağız.

6 Cevap

Perl TripleDESgereken asla kullanılmamalıdır. O kadar çok tuhaf şeyler yapar ve eğlenmek için gidiyoruz.

İlk sorun, Perl anahtarları onaltılık ve ikilik dönüştürmek için gereken olmasıdır. PHP, bu deneyin,

$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";

Sonuç olarak, bir

AYOF+kRtg239Mnyc8QIarw==

Sonra tuhaf bir şekilde pad onu var. Ben ayrıntılarını unuttum. Eğer (bu 16 karakter var) bu örnek ile şanslı.

Coldfusion Cevap:

İlk sorun, anahtar uzunluğu Üçlü DES için doğru değildir olmasıdır. ZZ Coder doğru durum 0 ile doğru uzunluğa yastıklı gerektiğini çıkarılabilir.

Bir sonraki adım, anahtar hex dönüştürülmesi gerekiyor. CF Bunu yapmak için, biz var:

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

Son adım sonuç ya boşluklarla varlık değildir ki, bu yüzden CF şifreleme algoritması bu belirtmeniz gerekir:

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

Oluşan tam kodu:

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

in sonuçları:

AYOF+kRtg239Mnyc8QIarw==

Oh, bu çok eğlenceli!

> 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

Sen e-posta listeleri openssl-kullanıcı veya dev-tech-kripto @ mozilla kişinin yararlı gösterileri sürece burada belki de deneyin, bir kripto uzmanı konuşmak gerekir.

ZZ Coder neredeyse yoktu. Perl ve PHP kodları, farklı şifreleme döndü neden daha sadece birkaç uyarılar var.

Geçersiz onaltılık harfler (F sonra harf) vardır zaman Birincisi, aşağıdaki kurala göre değiştirin:

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

Bu yöntemi kullanarak, AZ98AZ98AZ98AZ98AZ98AZ98 için anahtar (sıfır ile doldurma sonra) A398A398A398A398A398A398000000000000000000000000 olduğunu.

Karakter sayısı 8 ile bölünebilir böylece İkincisi, şifreli metin whitespaces doldurulur edilmelidir. Bu örnekte, username = test123 yüzden yastıklı olması gerekmez 8 ile bölünebilir. Ama username = test12 olsaydı, o zaman sonunda bir boşluk gerekiyor.

Aşağıdaki PHP kodu perl şifreleme eşleşen bir şifreleme döndürür

$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 />";

Bana bir akşam çoğunu aldı, ancak bu Eric Kigathi çözümü @ yakut görünüyor nasıl

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

Olsa da, dikkatli olmak yok. Ben + ve / sonunda dönüştürmek oldukça emin değilim. Ben 4 ve 5 de tahmin, ama bunun doğru olup olmadığını ben size söyleyemem.

Hat http://opensourcetester.co.uk/2012/11/29/zeros-padding-3des-ruby-openssl/ şifreleme kodu ve yorumlarına ucu.

: Crypt iki sorun (ya da değil) :: TripleDESgereken vardır

  1. Crypt :: TripleDES için tuşlar HEX olduğu gerçeği (önceki ZZ Coder tarafından açıklanmıştır). Ya kullanarak unpack veya Ord / sprintf veya diğer yöntemlerle bir demet kullanarak anahtarı HEX yapabilirsiniz:

    • $ = Unpack ("H *", "SİZİN PAROLA") geçmesi; # Pack / unpack versiyon

    • $ Pass = join ('', harita {sprintf ("% x", $ )} map { ord($)} bölünmüş (/ /, "SİZİN PASS"));

    Crypt :: TripleDESgereken (benim için ok) boşluklarla geçiş ifade pedleri

  2. Crypt :: TripleDESgereken sadece düz metin boşluk doldurma yapar. Java veya PHP MCRYPT_ENCRYPT üzerinde kullanılan çok sayıda dolgu yöntem vardır:

    • (Yani PKCS5, PKCS7, CMS) - bayt sayısını gösteren aynı değeri byte ile pad boşluklarla örn: "Andrei" -> hex: 61 6e 64 72 65 69 -> yastıklı: 61 6e 64 72 65 69 02 02
    • null karakterler ile pad örn: 61 6e 64 72 65 69 00 00
    • boşluklarla ped (Crypt :: TripleDESgereken zaten bunu yapar)
    • 61 6e 64 72 65 69 00 02: yastıklı bayt örn numarası olacaktır son bayt hariç sıfır (null karakter) ile pad
    • boş karakter tarafından takip 0x80 ile pad örn: 61 6e 64 72 65 69 80 00

Bazı noktaya kadar eşleşen ama sonun, farklı ise bir düz metin dolgu sorununuz varsa, sizin cypher-metne dikkat edin. Aksi takdirde bir geçiş ifade sorunu, bir cypher blok modu sorunu (EBC, CBC, ..) http://www.tools4noobs.com/online_tools/encrypt/help_modes.php ya da bir algoritma sorunu olabilir.

Peki ben Perl yaptım (null karakter dolgu kullanılır) Java cypher-metni eşleştirmek mümkün:

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 $cypher = $des->encrypt3( $text, $pass );

Umarım bu yardımcı olur