سؤال

والوضع أحاول حل: في بلدي التطبيق الكاكاو، ولست بحاجة لتشفير سلسلة مع تشفير متماثل، بعد ذلك إلى PHP، ويكون هذا السيناريو فك شفرة البيانات. وتحتاج العملية للعمل في الاتجاه المعاكس للعودة إجابة (PHP يشفر، الكاكاو يترجم).

وأنا في عداد المفقودين شيء لأنه حتى وإن يمكنني الحصول على كل من مفتاح وناقلات التهيئة ليكون (د) نفسه في كل PHP والكاكاو، فك أبدا يعمل عندما يرسل التطبيق واحد بياناتها المشفرة إلى أخرى. كل من عمل الترميز على ما يرام / فك البيانات الخاصة بها (التحقق للتأكد من لم يكن هناك بعض المسألة PEBKAC في متناول اليد). لدي شكوك أن هناك مكان قضية الحشو، وأنا لا أرى ذلك.

وبلدي الكاكاو التطبيق بترميز باستخدام SSCrypto (والذي هو مجرد غلاف مفيد-الطراز الأول حول وظائف بينسل). والشفرات هو السمكة المنتفخة، ووضع هو CBC. (يغفر للتسرب الذاكرة، وقد تم تجريد رمز إلى الضروريات)

NSData *secretText = [@"secretTextToEncode" dataUsingEncoding:NSUTF8StringEncoding];
NSData *symmetricKey = [@"ThisIsMyKey" dataUsingEncoding:NSUTF8StringEncoding];

unsigned char *input = (unsigned char *)[secretText bytes];
unsigned char *outbuf;
int outlen, templen, inlen;
inlen = [secretText length];

unsigned char evp_key[EVP_MAX_KEY_LENGTH] = {"\0"};
int cipherMaxIVLength = EVP_MAX_IV_LENGTH;
EVP_CIPHER_CTX cCtx;
const EVP_CIPHER *cipher = EVP_bf_cbc();

cipherMaxIVLength = EVP_CIPHER_iv_length( cipher );
unsigned char iv[cipherMaxIVLength];

EVP_BytesToKey(cipher, EVP_md5(), NULL, [symmetricKey bytes], [symmetricKey length], 1, evp_key, iv);

NSData *initVector = [NSData dataWithBytes:iv length:cipherMaxIVLength];

EVP_CIPHER_CTX_init(&cCtx);

if (!EVP_EncryptInit_ex(&cCtx, cipher, NULL, evp_key, iv)) {
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
int ctx_CipherKeyLength = EVP_CIPHER_CTX_key_length( &cCtx );
EVP_CIPHER_CTX_set_key_length(&cCtx, ctx_CipherKeyLength);

outbuf = (unsigned char *)calloc(inlen + EVP_CIPHER_CTX_block_size(&cCtx), sizeof(unsigned char));

if (!EVP_EncryptUpdate(&cCtx, outbuf, &outlen, input, inlen)){
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
if (!EVP_EncryptFinal(&cCtx, outbuf + outlen, &templen)){
    EVP_CIPHER_CTX_cleanup(&cCtx);
    return nil;
}
outlen += templen;
EVP_CIPHER_CTX_cleanup(&cCtx);

NSData *cipherText = [NSData dataWithBytes:outbuf length:outlen];

NSString *base64String = [cipherText encodeBase64WithNewlines:NO];
NSString *iv = [initVector encodeBase64WithNewlines:NO];

وbase64String والرابع ثم يتم نشرها إلى PHP الذي يحاول فك رموز ما يلي:

<?php

import_request_variables( "p", "p_" );

if( $p_data != "" && $p_iv != "" )
{
    $encodedData = base64_decode( $p_data, true );
    $iv = base64_decode( $p_iv, true );

    $td = mcrypt_module_open( MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '' );
    $keySize = mcrypt_enc_get_key_size( $td );
    $key = substr( md5( "ThisIsMyKey" ), 0, $keySize );

    $decodedData = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encodedData, MCRYPT_MODE_CBC, $iv );
    mcrypt_module_close( $td );

    echo "decoded: " . $decodedData;
}
?>

وdecodedData دائما رطانة.

ولقد حاولت عكس هذه العملية، وإرسال الناتج المشفرة من PHP الى كاكاو لكن EVP_DecryptFinal () فشل، وهو ما يقودني إلى الاعتقاد هناك قضية الحشو NULL في مكان ما. لقد قرأت وإعادة قراءة في PHP وبينسل مستندات ولكن كل شيء طمس معا الآن وأنا خارج من الأفكار لمحاولة.

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

المحلول

وأعتقد أن المشكلة هي أن طريقة اشتقاق مفتاح التشفير الخام من السلسلة الرئيسية مختلفة على الجانبين. وظيفة فب MD5 () بإرجاع سلسلة الست عشرية، أي بمعنى "a476c3 ... 'الذي يتم تقطيع وصولا الى حجم المفتاح، في حين EVP_BytesToKey () هو روتين تجزئة معقدة إلى حد ما التي ترجع سلسلة بايت الخام. وربما كان، مع المعلمات المتوفرة تبسيط وصولا الى تجزئة MD5 الخام، ولكن لا استطيع ان اقول حقا. وفي كلتا الحالتين، فإنه سوف يكون مختلفا عن تجزئة بي.

إذا قمت بتغيير بكود MD5 ( "ThisIsMyKey"، صحيح)، من شأنها أن تعطيك تجزئة MD5 الخام. على الجانب الكاكاو من الأشياء، SSCrypto ل+ getMD5ForData: طريقة أن يولد نفس واحدة لنفس سلسلة (قضايا ترميز النص جانبا)

.

وتحرير 1: إذا كان سلسلة فب والبيانات الكاكاو بطباعة مماثل، انهم ما زالوا مختلفين في مستوى بايت. سلسلة فب هو ترميز عرافة (أي يتكون فقط من أحرف 0-9 و-و) في حين أن البيانات الكاكاو هو بايت الخام (على الرغم من NSData يطبع مفيد من سلسلة المشفرة عرافة محتوياته عندما NSLogged). ما زالت هناك حاجة لإضافة المعلمة الحقيقة الثانية MD5 فب () لتعمل للحصول على سلسلة بايت الخام.

وتحرير 2: تغيرت بينسل 1.1.0c خوارزمية هضم وتستخدم في بعض المكونات الداخلية. سابقا، كانت تستخدم MD5، و1.1.0 تحولت إلى SHA256. كن حذرا التغيير لا تؤثر عليك في كل EVP_BytesToKey وأوامر مثل openssl enc.

نصائح أخرى

وأنا أحسب مشكلتي. الجواب باختصار: الكائن الرئيسية المستخدمة كانت من أطوال مختلفة تحت الكاكاو وPHP. الجواب طويلة ...

وبلدي التحقيق الأصلي كان يستخدم السمكة المنتفخة / CBC وهو متغير رئيسي طول الشفرات من 16 بايت إلى 56. الخروج من فكرة بوعز أن المفتاح كان بطريقة أو بأخرى إلى إلقاء اللوم، وتحولت إلى TripleDES لالشفرات كما يستخدم مفتاح ثابت طول 24 بايت. كان عليه ثم لاحظت وجود مشكلة: كان مفتاح عاد من الكاكاو / EVP_BytesToKey () 24 بايت في طول، ولكن القيمة التي تم إرجاعها من قبل MD5 () تجزئة مفتاحي 16 فقط

.

وكان الحل لهذه المشكلة أن يكون PHP إنشاء مفتاح نفس الطريقة EVP_BytesToKey يفعل حتى كان طول انتاج ما لا يقل عن (cipherKeyLength + cipherIVLength). وPHP التالية لا مجرد أن (تجاهل أي ملح أو العد التكرار)

$cipher = MCRYPT_TRIPLEDES;
$cipherMode = MCRYPT_MODE_CBC;

$keySize   = mcrypt_get_key_size( $cipher, $cipherMode );
$ivSize    = mcrypt_get_iv_size( $cipher, $cipherMode );

$rawKey = "ThisIsMyKey";
$genKeyData = '';
do
{
    $genKeyData = $genKeyData.md5( $genKeyData.$rawKey, true );
} while( strlen( $genKeyData ) < ($keySize + $ivSize) );

$generatedKey = substr( $genKeyData, 0, $keySize );
$generatedIV  = substr( $genKeyData, $keySize, $ivSize );

$output = mcrypt_decrypt( $cipher, $generatedKey, $encodedData, $cipherMode, $generatedIV );

echo "output (hex)" . bin2hex($output);

لاحظ أن الأرجح سوف يكون هناك PKCS # 5 الحشو على نهاية تلك المخرجات. تحقق من التعليقات هنا http://us3.php.net/manual/en /ref.mcrypt.php للحصول على pkcs5_pad وpkcs5_unpad لإضافة وإزالة وقال الحشو.

وأساسا، واتخاذ قيمة MD5 الخام من المفتاح وإذا كان ذلك ليست طويلة بما فيه الكفاية، إلحاق المفتاح إلى نتيجة MD5 MD5 وهذه السلسلة مرة أخرى. غسل، شطف، وتكرار. الصفحة رجل لEVP_BytesToKey () توضح ما تقوم به فعلا ويظهر فيها أحد من شأنه أن يضع القيم الملح، وإذا لزم الأمر. هذا الأسلوب من تجديد المفتاح أيضا تجدد بشكل صحيح متجه التهيئة (د) لذلك ليس من الضروري أن يمر على طول.

ولكن ماذا عن السمكة المنتفخة؟

وEVP_BytesToKey() إرجاع أصغر مفتاح ممكن لالشفرات كما أنها لا تقبل سياق التي يمكن من خلالها إسناد حجم المفتاح من. وبالتالي فإن حجم الافتراضي هو كل ما تحصل عليه، والتي لالسمكة المنتفخة هو 16 بايت. mcrypt_get_key_size()، من ناحية أخرى، يعود أكبر حجم ممكن الرئيسيين. لذلك الأسطر التالية في قانون بلدي الأصلي:

$keySize = mcrypt_enc_get_key_size( $td );
$key = substr( md5( "ThisIsMyKey" ), 0, $keySize );

وسيكون دائما العودة مفتاح 32 شخصية بسبب تعيين $ keySize إلى 56. تغيير التعليمات البرمجية أعلاه إلى:

$cipher = MCRYPT_BLOWFISH;
$cipherMode = MCRYPT_MODE_CBC;

$keySize   = 16;

ويسمح السمكة المنتفخة لفك بشكل صحيح ولكن الى حد كبير أنقاض صالح مفتاح طول متغير. وخلاصة القول، EVP_BytesToKey() مكسورة عندما يتعلق الأمر متغير الأصفار طول الرئيسية. تحتاج إلى إنشاء مفتاح / د بشكل مختلف عند استخدام الشفرات رئيسي متغير. أنا لم أذهب إلى ذلك كثيرا لأن 3DES ستعمل ما أحتاج.

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