php कैसे एईएस एन्क्रिप्टेड स्ट्रिंग से PKCS7 पैडिंग को जोड़ने/निकालने के लिए?




encryption aes (2)

मैंने पैडिंग और अनपैडिंग करने के लिए दो तरीके तैयार किए हैं I कार्यों को phpdoc का उपयोग करके प्रलेखित किया जाता है और PHP 5 की आवश्यकता होती है। जैसा कि आप देखेंगे कि अनपैड फ़ंक्शन में बहुत सारे अपवाद हैंडलिंग हैं, जो प्रत्येक संभव त्रुटि के लिए 4 से कम अलग-अलग संदेश नहीं पैदा करता है।

PHP mcrypt के लिए ब्लॉक आकार प्राप्त करने के लिए, आप mcrypt_get_block_size उपयोग कर सकते हैं, जो बिट्स के बजाए बाइट में होने के लिए ब्लॉक आकार को भी परिभाषित करता है

/**
 * Right-pads the data string with 1 to n bytes according to PKCS#7,
 * where n is the block size.
 * The size of the result is x times n, where x is at least 1.
 * 
 * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
 * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
 *
 * @param string $plaintext the plaintext encoded as a string containing bytes
 * @param integer $blocksize the block size of the cipher in bytes
 * @return string the padded plaintext
 */
function pkcs7pad($plaintext, $blocksize)
{
    $padsize = $blocksize - (strlen($plaintext) % $blocksize);
    return $plaintext . str_repeat(chr($padsize), $padsize);
}

/**
 * Validates and unpads the padded plaintext according to PKCS#7.
 * The resulting plaintext will be 1 to n bytes smaller depending on the amount of padding,
 * where n is the block size.
 *
 * The user is required to make sure that plaintext and padding oracles do not apply,
 * for instance by providing integrity and authenticity to the IV and ciphertext using a HMAC.
 *
 * Note that errors during uppadding may occur if the integrity of the ciphertext
 * is not validated or if the key is incorrect. A wrong key, IV or ciphertext may all
 * lead to errors within this method.
 *
 * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
 * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
 *
 * @param string padded the padded plaintext encoded as a string containing bytes
 * @param integer $blocksize the block size of the cipher in bytes
 * @return string the unpadded plaintext
 * @throws Exception if the unpadding failed
 */
function pkcs7unpad($padded, $blocksize)
{
    $l = strlen($padded);

    if ($l % $blocksize != 0) 
    {
        throw new Exception("Padded plaintext cannot be divided by the block size");
    }

    $padsize = ord($padded[$l - 1]);

    if ($padsize === 0)
    {
        throw new Exception("Zero padding found instead of PKCS#7 padding");
    }    

    if ($padsize > $blocksize)
    {
        throw new Exception("Incorrect amount of PKCS#7 padding for blocksize");
    }

    // check the correctness of the padding bytes by counting the occurance
    $padding = substr($padded, -1 * $padsize);
    if (substr_count($padding, chr($padsize)) != $padsize)
    {
        throw new Exception("Invalid PKCS#7 padding encountered");
    }

    return substr($padded, 0, $l - $padsize);
}

यह किसी भी तरह से पालो एबर्मान का जवाब अमान्य नहीं करता है, यह मूल रूप से कोड और phpdoc में वर्णन के बजाय एक ही उत्तर है।

ध्यान दें कि किसी आक्रमण करने वाले को एक गद्दी की गलती को लौटाने से एक पैडिंग ऑरेकल आक्रमण हो सकता है जो पूरी तरह से सीबीसी (जब ईसीबी के बजाय सीबीसी का उपयोग किया जाता है या सुरक्षित प्रमाणीकृत साइफर) को तोड़ता है।

मैं 128 बिट एईएस एन्क्रिप्शन (ईसीबी) का उपयोग कर एक स्ट्रिंग एन्क्रिप्ट / डिक्रिप्ट करने की कोशिश कर रहा हूं। मैं क्या जानना चाहता हूं कि मैं इसे पीकेसीएस 7 पैडिंग को कैसे जोड़ या हटा सकता हूं। ऐसा लगता है कि Mcrypt एक्सटेंशन एन्क्रिप्शन / डिक्रिप्शन का ध्यान रख सकता है, लेकिन पैडिंग को मैन्युअल रूप से जोड़ा / हटा दिया जाना चाहिए।

कोई विचार?


चलो देखते हैं। पीकेसीएस # 7 आरएफसी 5652 (क्रिप्टोग्राफिक संदेश सिंटैक्स) में वर्णित है।

पैडिंग योजना स्वयं ही खंड 6.3 में दी गई है सामग्री-एन्क्रिप्शन प्रक्रिया यह अनिवार्य रूप से कहता है: दिए गए ब्लॉक आकार (लेकिन कम से कम एक) को भरने के लिए आवश्यक कई बाइटों को जोड़ें, और उनमें से प्रत्येक को पैडिंग लंबाई को मूल्य के रूप में होना चाहिए।

इस प्रकार, पिछले डिक्रिप्टेड बाइट को देखते हुए हम जानते हैं कि कितने बाइट्स को पट्टी करना है। (एक यह भी देख सकता है कि वे सभी एक ही मान हैं।)

मैं अब आपको ऐसा करने के लिए PHP फ़ंक्शन की एक जोड़ी दे सकता था, लेकिन मेरा PHP थोड़ी सी जंगली है। इसलिए या तो खुद को करें (फिर इसे जोड़ने के लिए अपने जवाब को संपादित करने के लिए बेझिझक), या एमक्रीप्प्ट दस्तावेज में यूज़र-योगदान वाले नोट्स पर नज़र डालें- उनमें से कुछ पैडिंग के बारे में हैं और पीकेसीएस # 7 पैडिंग का कार्यान्वयन ।

तो, हम पहले नोट को विस्तार से देखें:

<?php

function encrypt($str, $key)
 {
     $block = mcrypt_get_block_size('des', 'ecb');

यह प्रयोग किए गए एल्गोरिथम के ब्लॉक आकार को प्राप्त करता है। आपके मामले में, आप rijndael_128 या rijndael_128 बजाय des का उपयोग करेंगे, मुझे लगता है (मैं इसे परीक्षण नहीं किया था)। (इसके बजाय, आप फ़ंक्शन को लागू करने के बजाय बस एईएस के लिए 16 ले सकते थे।)

     $pad = $block - (strlen($str) % $block);

यह पैडिंग आकार की गणना करता है strlen($str) आपके डेटा की लंबाई (बाइट्स) में है, % $block शेष मॉड्यूलो $block , अर्थात पिछले ब्लॉक में डाटा बाइट्स की संख्या। $block - ... इस प्रकार इस अंतिम ब्लॉक को भरने के लिए आवश्यक बाइट्स की संख्या देता है (यह अब 1 और $block , समावेशी के बीच की संख्या है)।

     $str .= str_repeat(chr($pad), $pad);

str_repeat एक स्ट्रिंग का निर्माण करता है जिसमें एक स्ट्रिंग की पुनरावृत्ति होती है, यहां $pad , $pad बार, अर्थात $pad की स्ट्रिंग, $pad से भरा वर्ण का दोहराव। $str .= ... मूल चित्र में इस पेडिंग स्ट्रिंग को जोड़ता है

     return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

यहाँ एन्क्रिप्शन ही है MCRYPT_RIJNDAEL_128 बजाय MCRYPT_RIJNDAEL_128 उपयोग करें

 }

अब दूसरी दिशा:

 function decrypt($str, $key)
 {   
     $str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

डिक्रिप्शन (आप निश्चित रूप से उपरोक्त के रूप में, एल्गोरिथ्म बदल जाएगा)। $ str अब डिक्रिप्टेड स्ट्रिंग है, जिसमें पैडिंग भी शामिल है

     $block = mcrypt_get_block_size('des', 'ecb');

यह फिर से ब्लॉक आकार है। (ऊपर देखो।)

     $pad = ord($str[($len = strlen($str)) - 1]);

यह थोड़ा अजीब लगता है बेहतर इसे कई चरणों में लिखें:

    $len = strlen($str);
    $pad = ord($str[$len-1]);

$len अब गद्देदार स्ट्रिंग की लंबाई है, और $str[$len - 1] इस स्ट्रिंग का अंतिम वर्ण है। ord एक संख्या में यह धर्मान्तरित। इस प्रकार $pad संख्या है जिसे हम पहले पैडिंग के लिए भरण मूल्य के रूप में इस्तेमाल करते थे, और यह पैडिंग लंबाई है

     return substr($str, 0, strlen($str) - $pad);

तो अब हमने स्ट्रिंग से अंतिम $pad बाइट काट कर दिया है। ( strlen($str) बजाय हम यहां $len भी लिख सकते हैं: substr($str, 0, $len - $pad) ।)

 }

?>

नोट करें कि substr($str, $len - $pad) का उपयोग करने के बजाय, कोई भी substr($str, -$pad) लिख सकता है, क्योंकि PHP में substr फ़ंक्शन नकारात्मक ऑपरेटों / तर्कों के लिए एक विशेष-हैंडलिंग है, स्ट्रिंग के अंत से (मुझे नहीं पता कि यह पहले की लंबाई प्राप्त करने और मैन्युअल रूप से सूचकांक की तुलना में अधिक या कम कुशल है।)

जैसा कि पहले कहा गया था और रोस्सुम की टिप्पणी में लिखा था, यहाँ की तरह पैडिंग को छीनने की बजाए, आपको यह जांचना चाहिए कि यह सही है- यानी substr($str, $len - $pad) को देखो, और जांच लें कि इसकी सभी बाइट्स chr($pad) । यह भ्रष्टाचार के खिलाफ मामूली जांच के रूप में कार्य करता है (हालांकि यह जांच अधिक प्रभावी है यदि आप ईसीबी के बजाय शृंखला का उपयोग करते हैं, और असली मैक के बदले नहीं)।

(और फिर भी, अपने ग्राहक को बताएं कि उन्हें ईसीबी की तुलना में अधिक सुरक्षित मोड में बदलने के बारे में सोचना चाहिए।)





pkcs#7