سؤال

نشأت مشكلة في الآونة الأخيرة فيما يتعلق بتثبيت واجهة برمجة التطبيقات مع معالج الدفع الذي كان يطلب سلسلة من تشفيرها لاستخدامها كرمز ، باستخدام معيار Tripledes. يتم تشغيل تطبيقاتنا باستخدام ColdFusion ، التي تحتوي على علامة تشفير - تدعم ثلاث مرات - ومع ذلك فإن النتيجة التي كنا نعود إليها لم تكن كما توقع معالج الدفع.

بادئ ذي بدء ، إليك الرمز المميز الناتج الذي كان يتوقعه معالج الدفع.

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 لدينا تؤدي إلى السلسلة الصحيحة. بعد البحث السريع ، وافق أيضًا على أنه لم يكن مصدرنا بشكل أساسي ، بل كيف نفذت اللغتان رؤيتهما لمعايير Tripedes.

عند الوصول إلى المكتب هذا الصباح ، قابلنا بريدًا إلكترونيًا مع مقتطف من التعليمات البرمجية المصدر ، في 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 ، هل تمكنت من الحصول على أي اثنين منهم لإعطاء نفس الرد ، وإذا كان الأمر كذلك ، فما هو التعديلات على الرمز الذي يجب عليك فعله بالترتيب للوصول إلى النتيجة؟

أتفهم أن هذا سؤال مرسوم للغاية ، لكنني أردت أن أعطي إعدادًا واضحًا ودقيقًا لكل مرحلة من مراحل الاختبار التي كان علينا القيام بها.

سأقوم أيضًا بأداء المزيد من الأعمال الاستقصائية حول هذا الموضوع لاحقًا ، وسأقوم بنشر أي نتائج أتوصل إليها إلى هذا السؤال ، حتى يتمكن الآخرون من تجنب هذا الصداع.

هل كانت مفيدة؟

المحلول

لا ينبغي استخدام ثلاث مرات بيرل. إنها تفعل الكثير من الأشياء الغريبة وستستمتع.

مشكلتك الأولى هي أن مفاتيح Perl هي Hex وتحتاج إلى تحويلها إلى ثنائي. جرب هذا في 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 Chars).

نصائح أخرى

إجابة Coldfusion:

المشكلة الأولى هي أن طول المفتاح الخاص بك غير صحيح بالنسبة لـ Triple des. استنتج ZZ Coder بشكل صحيح أنه يحتاج إلى مبطنة للطول الصحيح مع 0.

والخطوة التالية هي أنه يجب تحويل المفتاح إلى Hex. للقيام بذلك في 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>

النتائج في:

AYOF+kRtg239Mnyc8QIarw==

سأقوم بتضمين الرمز أدناه لأي شخص يعمل على ترقية CCBill (والذي يبدو أن الشركة المشار إليها في المنشور الأصلي). ستطابق وظائف PHP أدناه الإخراج من التشفير الداخلي لـ CCBILL 3DES/TREPLED كما هو موضح في الوثائق هنا: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

أوه ، هذا ممتع!

> 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 أو مستخدمي Dev-Tech-Crypto@Mozilla ما لم يظهر شخص مفيد هنا.

كان ZZ Coder هناك تقريبًا. لا يوجد سوى عدد قليل من التحذيرات إلى سبب قيام رموز Perl و PHP بإعادة تشفيرات مختلفة.

أولاً ، كلما كانت هناك رسائل سداسية غير صالحة (رسائل بعد و) ، استبدلها وفقًا للقاعدة التالية:

  • g-> 0
  • H-> 1
  • i-> 2
  • J-> 3
  • ...
  • p-> 9
  • س-> أ
  • ص-> ب
  • ...
  • v-> f
  • w-> 0
  • ...
  • Z-> 3

باستخدام هذه الطريقة ، فإن مفتاح AZ98AZ98AZ98AZ98AZ98AZ98 هو A398A398A398A398A398A39880000000000000000000000 (بعد الحشو مع الأصفار).

ثانياً ، يجب أن يكون النص المراد تشفيره مبطنًا بأماكن بيضاء بحيث يكون عدد الأحرف قابلة للقسمة على 8. في هذا المثال ، اسم المستخدم = Test123 قابل للقسمة على 8 ، لذلك لا يلزم أن يكون مبدعًا. ولكن ، إذا كان اسم المستخدم = test12 ، فإنه يحتاج إلى مساحة بيضاء واحدة في النهاية.

يعيد رمز PHP التالي تشفيرًا يطابق تشفير Perl

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

أخذني أكثر من أمسية ، ولكن هذا هو ما يبدو عليه حل @Eric Kigathi في 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

كن حذرا ، رغم ذلك. لست متأكدًا تمامًا من ما هو + و / / يتحول في النهاية. لقد خمنت في 4 و 5 ، لكن لا يمكنني إخبارك إذا كان هذا صحيحًا.

نصيحة قبعة ل http://opensourcetester.co.uk/2012/11/29/zeros-padding-3des-ruby-openssl/ رمز التشفير والتعليق.

تفقد إجابة Coldfusion تعديل مفتاح CCBILL للعمل (كما هو الحال في إجابة إريك) ... لقد قمت بتعديل إجابة إريك على رمز Lucee. لا ينبغي أن يتطلب الأمر الكثير من العمل لاستعادته إلى التعليمات البرمجية المتوافقة مع ACF (تغيير الهيكل في Relacenocase مع الفردية).

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);
}

هناك مشكلتان (أو لا) مع Crypt :: Tripledes:

  1. حقيقة أن مفاتيح Crypt :: Tripledes هي Hex (أوضحت في وقت سابق من قبل ZZ المبرمج). يمكنك سداسية مفتاحك إما عن طريق استخدام إلغاء الافتحة أو باستخدام Ord/Sprintf أو مجموعة من الطرق الأخرى:

    • $ pass = unpack ("h*" ، "your passphrase") ؛ #حزمة/إصدار إصدار

    • $ pass = join ('' ، Map {Sprintf ("٪ x" ، $)} خريطة {ord ($)} split (// ، "الخاص بك")) ؛

    Crypt :: Tripedes Pads عبارة تمريرة مع المسافات (التي كانت على ما يرام بالنسبة لي)

  2. Crypt :: Tripledes يقوم بمساحة بيضاء فقط من النص العادي. هناك العديد من طرق الحشو التي يتم استخدامها على Java أو PHP MCRYPT_ENCRYPT:

    • (أي PKCS5 ، PKCS7 ، CMS) -PAD مع بايت من نفس القيمة التي تشير إلى عدد البايتات المبطنة على سبيل المثال: "Andrei" -> Hex: 61 6e 64 72 65 69 -> مبطن: 61 64 72 65 69 02 02 02
    • لوحة مع أحرف خالية على سبيل المثال: 61 6e 64 72 65 69 00 00
    • وسادة مع مسافات (crypt :: tripledes بالفعل يفعل هذا)
    • Pad with Zeros (Null Chars) باستثناء البايت الأخير الذي سيكون عدد البايتات المبطنة على سبيل المثال: 61 6e 64 72 69 00 02
    • لوحة مع 0x80 تليها chars null على سبيل المثال: 61 6e 64 72 65 69 80 00

انتبه إلى نص Cipher الخاص بك ، إذا كان متطابقًا حتى نقطة ما ولكن النهاية مختلفة ، فأنت تعاني من مشكلة في حشوة النص العادي. وإلا فقد يكون لديك مشكلة في عبارة المرور ، ومشكلة وضع كتلة التشفير (EBC ، CBC ، ..) http://www.tools4noobs.com/online_tools/encrypt/help_modes.php أو مشكلة الخوارزمية.

إذن ما فعلته في بيرل لتكون قادرًا على مطابقة النص المشفر من Java (الذي استخدم حشوة Null Chars):

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

أتمنى أن يساعدك هذا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top