कोको में डेटा एन्क्रिप्ट, PHP में डीकोडिंग(और इसके विपरीत)




cocoa encryption (2)

मैं जिस स्थिति को हल करने की कोशिश कर रहा हूं: मेरे कोको ऐप में, मुझे एक स्ट्रिंग को एक सममित सिफर के साथ एन्क्रिप्ट करने की आवश्यकता है, इसे PHP पर पोस्ट करें, और उस स्क्रिप्ट को डेटा को डीकोड करें। इस प्रक्रिया को एक उत्तर (PHP एन्कोड्स, कोको डिकोड) लौटने के लिए रिवर्स में काम करना होगा।

मुझे कुछ याद आ रहा है क्योंकि भले ही मैं दोनों कुंजी और आरंभीकरण वेक्टर (iv) दोनों PHP और कोको में एक ही हो सकता है, डिकोडिंग कभी काम नहीं करता है जब एक ऐप अपने एन्कोडेड डेटा को दूसरे को भेजता है दोनों ही काम ठीक एन्कोडिंग / अपने खुद के डेटा decoding (यह सुनिश्चित करने के लिए सत्यापित है कि हाथ में कुछ PEBKAC मुद्दा नहीं था)। मुझे संदेह है कि कोई पेडिंग मुद्दा कहीं है, मैं इसे देख नहीं पाया।

मेरी कोका ऐप एसकक्रिप्टो (जो कि ओपनएसएसएल फ़ंक्शंस के आस-पास एक आसान-बांका आवरण है) का उपयोग कर एन्कोड करता है। सिफर ब्लॉफिश है, मोड सीबीसी है (स्मृति लीक को क्षमा करें, कोड बेर अनिवार्य करने के लिए छीन लिया गया है)

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 और iv तब 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;
}
?>

डीकोडेडडेटा हमेशा व्यर्थ है

मैंने इस प्रक्रिया को पीछे करने की कोशिश की है, PHP से कोको के एन्कोडेड आउटपुट भेजने पर EVP_DecryptFinal () विफल रहता है, जो कि मुझे लगता है कि कहीं नल पैडिंग समस्या कहीं है। मैंने पीएचपी और ओपनएसएसएल दस्तावेज़ों को पढ़ा और पुनः पढ़ लिया है लेकिन यह सब अब एक साथ धुंधला हो रहा है और मैं कोशिश करने के लिए विचारों से बाहर हूं।


मैंने अपनी समस्या का पता लगाया संक्षिप्त उत्तर: कोको और PHP के तहत इस्तेमाल की जाने वाली चाबी अलग-अलग लंबाई की थी। लंबा जवाब ...

मेरी मूल जांच ब्लॉफिश / सीबीसी का उपयोग कर रही थी जो कि 16 बाइट्स से 56 तक एक चर कुंजी लंबाई है। बोअज़ के विचार से यह बात सामने आ रही है कि कुंजी किसी तरह का दोष थी, मैं सिफर के लिए ट्रिपल डीईएस पर स्विच कर रहा था क्योंकि यह 24 की एक निश्चित कुंजी लंबाई का उपयोग करता है बाइट्स। यह तब था जब मैंने एक समस्या देखी: कोको / ईवीपीबाइट्सटेकी () द्वारा लौटायी जाने वाली कुंजी 24 बाइट्स लंबाई में थी, लेकिन एमडी 5 () द्वारा मुहैया की गई मूल्य मेरी चाबी केवल 16 थी।

समस्या का हल PHP को एक कुंजी बनाने के लिए इसी तरह EVP_BytesToKey करता है जब तक कि उत्पादन की लंबाई कम से कम (सिफरकी लांघ + साइप्रिलाव लैंग) थी। निम्नलिखित पीएचपी सिर्फ इतना है कि (किसी भी नमक को नजरअंदाज करना या पुनरावृत्तियों की गिनती)

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

ध्यान दें कि उस आउटपुट के अंत में पीकेसीएस # 5 पैडिंग की संभावना अधिक होगी यहां टिप्पणियां देखें: http://us3.php.net/manual/en/ref.mcrypt.php pkcs5_pad और pkcs5_unpad लिए कहा गया है जोड़ने और हटाने के लिए पैडिंग

असल में, कुंजी के कच्चे एमडी 5 मान लेते हैं और यदि यह पर्याप्त नहीं है, तो एमडी 5 परिणाम की कुंजी और एमडी 5 को फिर से स्ट्रिंग जोड़ें। धुलाई, कुल्ला, दोहराना EVP_BytesToKey () के लिए मैन पेज बताता है कि यह वास्तव में क्या कर रहा है और दिखाता है कि एक को नमक मूल्यों को कहां रखा जाएगा, यदि आवश्यक हो कुंजी को पुनर्जन्म करने की यह विधि सही ढंग से प्रारंभिक वेक्टर (iv) को पुन: उत्पन्न करती है, इसलिए इसे पास करना आवश्यक नहीं है।

लेकिन ब्लोफिश के बारे में क्या?

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() टूटी हुई है जब यह वैरिएबल कुंजी लंबाई सिफर की बात आती है। एक चर कुंजी सिफर का उपयोग करते समय आपको एक कुंजी / iv भिन्न बनाने की आवश्यकता है मैं इसमें बहुत कुछ नहीं मिला क्योंकि 3DES जो काम की आवश्यकता है उसके लिए काम करेंगे।


मुझे लगता है कि आपकी समस्या यह है कि कुंजी स्ट्रिंग से कच्चे एन्क्रिप्शन कुंजी लाने की विधि दोनों पक्षों पर अलग है। Php md5 () फ़ंक्शन एक हेक्साडेसिमल स्ट्रिंग देता है, अर्थात 'a476c3 ...' जिसे आप कुंजी आकार में काट रहे हैं, जबकि EVP_BytesToKey () एक काफी जटिल हैश दिनचर्या है जो कच्चे बाइट स्ट्रिंग लौटाता है। यह हो सकता है कि मापदंडों के साथ कच्चे एमडी 5 हैश में सरल हो, लेकिन मैं वास्तव में नहीं बता सकता किसी भी तरह से, यह php हैश से अलग होने जा रहा है।

यदि आप php को md5 ("यह आईस्मेकी", TRUE) में बदलते हैं, जो आपको एक कच्चा एमडी 5 हैश देगा। चीजों की कोको ओर, SSCrypto's + getMD5ForData: विधि एक ही स्ट्रिंग के लिए एक ही उत्पन्न करना चाहिए (पाठ एन्कोडिंग मुद्दों को अलग करना)।

1 संपादित करें: यदि php स्ट्रिंग और कोको डेटा समान रूप से मुद्रित करते हैं, तो वे बाइट स्तर पर अभी भी अलग हैं। पीएचपी स्ट्रिंग हेक्स-एन्कोडेड है (यानी केवल 0- 9 और एफई), जबकि कोको डेटा कच्चा बाइट्स है (हालांकि एनएसडीटा सहायतापूर्वक हेक्स-एन्कोडेड स्ट्रिंग को एनएसएलॉग किए गए सामग्री की छापता है)। कच्चे बाइट स्ट्रिंग प्राप्त करने के लिए आपको अभी भी दूसरे TRUE पैरामीटर को php के md5 () फ़ंक्शन में जोड़ना होगा।

2 संपादित करें: ओपनएसएसएल 1.1.0 सी ने डायजेस्ट एल्गोरिथम बदल दिया है ( एन्क्रिप्शन / डिक्रिप्शन दो अलग-अलग एक्सप्लॉएसएल संस्करणों के बीच अच्छी तरह से काम नहीं करता है ) कुछ आंतरिक घटकों में उपयोग किया जाता है पूर्व में, MD5 का उपयोग किया गया था, और 1.1.0 SHA256 पर स्विच किया गया था। सावधान रहें कि परिवर्तन EVP_BytesToKey और आज्ञाओं दोनों में आपको प्रभावित नहीं कर रहा है जैसे कि openssl enc





mcrypt