PHP का उपयोग करके सबसे सरल दो-तरफ़ा एन्क्रिप्शन


230

सामान्य PHP इंस्टॉल में दो तरह से एन्क्रिप्शन करने का सबसे सरल तरीका क्या है?

मुझे एक स्ट्रिंग कुंजी के साथ डेटा एन्क्रिप्ट करने में सक्षम होने की आवश्यकता है, और दूसरे छोर पर डिक्रिप्ट करने के लिए उसी कुंजी का उपयोग करें।

सुरक्षा कोड के पोर्टेबिलिटी के रूप में एक चिंता का विषय नहीं है, इसलिए मैं चीजों को यथासंभव सरल रखने में सक्षम होना चाहता हूं। वर्तमान में, मैं एक RC4 कार्यान्वयन का उपयोग कर रहा हूं, लेकिन अगर मुझे कुछ मूल रूप से समर्थित I आंकड़ा मिल सकता है तो मैं बहुत सारे अनावश्यक कोड को बचा सकता हूं।



3
सामान्य प्रयोजन के एन्क्रिप्शन के लिए, डिफ्यूज़ / php-एन्क्रिप्शन / का उपयोग करें बजाय अपने स्वयं के रोल करने के।
स्कॉट आर्किसेवस्की

2
Github.com/defuse/php-enc एन्क्रिप्शन से दूर हाथ - यह mcrypt की तुलना में परिमाण के क्रम से धीमा है।
यूजेन रीक

1
@ "यह" शायद अड़चन नहीं होगी "की तर्ज पर यह सोचकर कि हमारे लिए बहुत से खराब सॉफ्टवेयर हैं।
यूजेन रीक

3
यदि आप वास्तव में बहुत सारे डेटा को इस बिंदु पर एन्क्रिप्ट / डिक्रिप्ट कर रहे हैं कि मिलीसेकंड यह आपके आवेदन की लागत को कम करता है, तो बुलेट को काटें और libsodium पर स्विच करें। Sodium::crypto_secretbox()और Sodium::crypto_secretbox_open()सुरक्षित और प्रदर्शन कर रहे हैं।
स्कॉट आर्किसेवस्की

जवाबों:


196

संपादित:

आपको वास्तव में Opensl_encrypt () और opensl_decrypt () का उपयोग करना चाहिए

जैसा कि स्कॉट कहते हैं, मैक्रिप्ट एक अच्छा विचार नहीं है क्योंकि यह 2007 के बाद से अपडेट नहीं किया गया है।

PHP से Mcrypt को हटाने के लिए RFC भी है - https://wiki.php.net/rfc/mcrypt-viking-funeral


6
@EugenRieck हाँ, यह बात है। Mcrypt पैच प्राप्त नहीं करता है। OpenSSL किसी भी भेद्यता का पता चलते ही पैच प्राप्त करता है, बड़ा या छोटा।
ग्रेग

5
इस तरह के उच्च मतदान वाले उत्तर के लिए बेहतर होगा कि उत्तर में भी सरलतम उदाहरण दिए जाएं। फिर भी धन्यवाद।
टोडुआ

दोस्तों, सिर्फ FYI => MCRYPT को DEPRECATED है। इसलिए हम सभी को यह जानना चाहिए कि इसका इस्तेमाल न करें क्योंकि इससे हमें कई मुद्दों का सामना करना पड़ता है। अगर यह गलत नहीं है तो यह PHP 7.1 के बाद से हटा दिया गया है।
क्लस्टरबडी

PHP 7 के बाद से mcrypt फ़ंक्शन php कोडबेस से हटा दिया जाता है। इसलिए जब आप php के नवीनतम संस्करण का उपयोग कर रहे हैं (जो मानक होना चाहिए) तो आप अब इस पदावनत समारोह का उपयोग करने में सक्षम नहीं हैं।
अलेक्जेंडर बेह्लिंग ने

234

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

सूचित रहें। सुरक्षित सिस्टम डिजाइन करें।

PHP में पोर्टेबल डेटा एन्क्रिप्शन

यदि आप PHP 5.4 या नए का उपयोग कर रहे हैं और स्वयं क्रिप्टोग्राफी मॉड्यूल नहीं लिखना चाहते हैं, तो मैं एक मौजूदा लाइब्रेरी का उपयोग करने की सलाह देता हूं जो प्रमाणित एन्क्रिप्शन प्रदान करता है । मैंने जो लाइब्रेरी कनेक्ट की है, वह केवल उसी पर निर्भर करती है, जो PHP प्रदान करता है और कुछ मुट्ठी भर सुरक्षा शोधकर्ताओं द्वारा समय-समय पर समीक्षा की जाती है। (खुद शामिल हैं।)

यदि आपके पोर्टेबिलिटी लक्ष्य PECL एक्सटेंशन की आवश्यकता को नहीं रोकते हैं, तो libsodium को किसी भी चीज़ पर अत्यधिक अनुशंसित किया जाता है जिसे आप PHP में लिख सकते हैं।

अद्यतन (2016-06-12): आप अब PECL एक्सटेंशन स्थापित किए बिना ही सोडियम_कामपेट का उपयोग कर सकते हैं और समान क्रिप्टोकरंसी ऑफर का उपयोग कर सकते हैं ।

यदि आप क्रिप्टोग्राफी इंजीनियरिंग में अपना हाथ आजमाना चाहते हैं, तो पढ़ें।


सबसे पहले, आपको अनधिकृत एन्क्रिप्शन और क्रिप्टोग्राफिक डूम सिद्धांत के खतरों को जानने के लिए समय निकालना चाहिए ।

  • एन्क्रिप्ट किए गए डेटा को अभी भी एक दुर्भावनापूर्ण उपयोगकर्ता द्वारा छेड़छाड़ किया जा सकता है।
  • एन्क्रिप्ट किए गए डेटा का प्रमाणीकरण छेड़छाड़ को रोकता है।
  • अनएन्क्रिप्टेड डेटा को प्रमाणित करने से छेड़छाड़ को रोका नहीं जा सकता है।

एन्क्रिप्शन और डिक्रिप्शन

PHP में एन्क्रिप्शन वास्तव में सरल है (हम उपयोग करने जा रहे हैं openssl_encrypt()और openssl_decrypt()एक बार जब आप अपनी जानकारी को एन्क्रिप्ट करने के तरीके के बारे में कुछ निर्णय लेते हैं, तो openssl_get_cipher_methods()अपने सिस्टम पर समर्थित तरीकों की सूची के लिए परामर्श करें । सबसे अच्छा विकल्प सीटीआर मोड में एईएस है :

  • aes-128-ctr
  • aes-192-ctr
  • aes-256-ctr

वर्तमान में यह मानने का कोई कारण नहीं है कि एईएस कुंजी आकार के बारे में चिंता करने के लिए एक महत्वपूर्ण मुद्दा है (बड़ा शायद बेहतर नहीं है, 256-बिट मोड में खराब की-शेड्यूलिंग के कारण)।

ध्यान दें: हम उपयोग नहीं कर रहे हैं mcryptक्योंकि यह परित्याग है और इसमें अप्रकाशित कीड़े हैं जो सुरक्षा-प्रभावित हो सकते हैं। इन कारणों के कारण, मैं अन्य PHP डेवलपर्स को भी इससे बचने के लिए प्रोत्साहित करता हूं।

OpenSSL का उपयोग करके सरल एन्क्रिप्शन / डिक्रिप्शन रैपर

class UnsafeCrypto
{
    const METHOD = 'aes-256-ctr';

    /**
     * Encrypts (but does not authenticate) a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded 
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = openssl_random_pseudo_bytes($nonceSize);

        $ciphertext = openssl_encrypt(
            $message,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );

        // Now let's pack the IV and the ciphertext together
        // Naively, we can just concatenate
        if ($encode) {
            return base64_encode($nonce.$ciphertext);
        }
        return $nonce.$ciphertext;
    }

    /**
     * Decrypts (but does not verify) a message
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        $nonceSize = openssl_cipher_iv_length(self::METHOD);
        $nonce = mb_substr($message, 0, $nonceSize, '8bit');
        $ciphertext = mb_substr($message, $nonceSize, null, '8bit');

        $plaintext = openssl_decrypt(
            $ciphertext,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $nonce
        );

        return $plaintext;
    }
}

उपयोग उदाहरण

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

डेमो : https://3v4l.org/jl7qR


उपरोक्त सरल क्रिप्टो लाइब्रेरी अभी भी उपयोग करने के लिए सुरक्षित नहीं है। हमें डिक्रिप्ट को प्रमाणित करने और डिक्रिप्ट करने से पहले उन्हें सत्यापित करने की आवश्यकता है

नोट : डिफ़ॉल्ट रूप से, UnsafeCrypto::encrypt()एक कच्चा बाइनरी स्ट्रिंग लौटाएगा। यदि आप इसे बाइनरी-सुरक्षित प्रारूप (बेस 64-एन्कोडेड) में संग्रहीत करना चाहते हैं, तो इसे इस तरह से कॉल करें:

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = UnsafeCrypto::encrypt($message, $key, true);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key, true);

var_dump($encrypted, $decrypted);

डेमो : http://3v4l.org/f5K93

सरल प्रमाणीकरण आवरण

class SaferCrypto extends UnsafeCrypto
{
    const HASH_ALGO = 'sha256';

    /**
     * Encrypts then MACs a message
     * 
     * @param string $message - plaintext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encode - set to TRUE to return a base64-encoded string
     * @return string (raw binary)
     */
    public static function encrypt($message, $key, $encode = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);

        // Pass to UnsafeCrypto::encrypt
        $ciphertext = parent::encrypt($message, $encKey);

        // Calculate a MAC of the IV and ciphertext
        $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);

        if ($encode) {
            return base64_encode($mac.$ciphertext);
        }
        // Prepend MAC to the ciphertext and return to caller
        return $mac.$ciphertext;
    }

    /**
     * Decrypts a message (after verifying integrity)
     * 
     * @param string $message - ciphertext message
     * @param string $key - encryption key (raw binary expected)
     * @param boolean $encoded - are we expecting an encoded string?
     * @return string (raw binary)
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        list($encKey, $authKey) = self::splitKeys($key);
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        // Hash Size -- in case HASH_ALGO is changed
        $hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
        $mac = mb_substr($message, 0, $hs, '8bit');

        $ciphertext = mb_substr($message, $hs, null, '8bit');

        $calculated = hash_hmac(
            self::HASH_ALGO,
            $ciphertext,
            $authKey,
            true
        );

        if (!self::hashEquals($mac, $calculated)) {
            throw new Exception('Encryption failure');
        }

        // Pass to UnsafeCrypto::decrypt
        $plaintext = parent::decrypt($ciphertext, $encKey);

        return $plaintext;
    }

    /**
     * Splits a key into two separate keys; one for encryption
     * and the other for authenticaiton
     * 
     * @param string $masterKey (raw binary)
     * @return array (two raw binary strings)
     */
    protected static function splitKeys($masterKey)
    {
        // You really want to implement HKDF here instead!
        return [
            hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
            hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
        ];
    }

    /**
     * Compare two strings without leaking timing information
     * 
     * @param string $a
     * @param string $b
     * @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
     * @return boolean
     */
    protected static function hashEquals($a, $b)
    {
        if (function_exists('hash_equals')) {
            return hash_equals($a, $b);
        }
        $nonce = openssl_random_pseudo_bytes(32);
        return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
    }
}

उपयोग उदाहरण

$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');

$encrypted = SaferCrypto::encrypt($message, $key);
$decrypted = SaferCrypto::decrypt($encrypted, $key);

var_dump($encrypted, $decrypted);

डेमो : कच्चा बाइनरी , बेस 64-एनकोडेड


यदि कोई इस SaferCryptoपुस्तकालय का उत्पादन वातावरण में उपयोग करना चाहता है, या आपकी स्वयं की अवधारणाओं को लागू करना है, तो मैं दृढ़ता से आपके निवासी क्रिप्टोग्राफ़रों तक पहुंचने से पहले आपको एक दूसरी राय देने की सलाह देता हूं। वे आपको उन गलतियों के बारे में बता पाएंगे, जिनके बारे में मुझे पता भी नहीं होगा।

एक प्रतिष्ठित क्रिप्टोग्राफी लाइब्रेरी का उपयोग करके आप बहुत बेहतर होंगे ।


3
इसलिए, मैं सिर्फ UnsafeCrypto को काम में लाने की कोशिश कर रहा हूं। एन्क्रिप्शन ठीक होता है, लेकिन हर बार जब मैं डिक्रिप्ट चलाता हूं, तो मुझे प्रतिक्रिया के रूप में 'गलत' मिल रहा है। मैं डिक्रिप्ट करने के लिए एक ही कुंजी का उपयोग कर रहा हूं, और एन्कोड पर, साथ ही डिकोड पर सच गुजर रहा है। वहाँ है, जो मैं मानता हूं कि उदाहरण में एक टाइपो है, मैं सोच रहा हूं कि क्या मेरी समस्या यह है कि कहां से आ रही है। क्या आप समझा सकते हैं कि $ मैक चर कहाँ से आ रहा है, और क्या यह केवल $ iv होना चाहिए?
डेविड सी।

1
@EugenRieck OpenSSL सिफर कार्यान्वयन शायद ही ऐसे हिस्से हैं जो चूसना नहीं करते हैं, और यह वेनिला PHP में एईएस-एनआई का लाभ उठाने का एकमात्र तरीका है। यदि आप OpenBSD पर स्थापित होते हैं, तो PHP को PHP कोड के बिना संकलित किया जाएगा, जिसमें PHP कोड अंतर के बिना दिखाई देगा। लिबसोडियम> ओपनएसएसएल किसी भी दिन। इसके अलावा, libmcrypt का उपयोग न करेंआप OpenSSL के बजाय PHP डेवलपर्स का उपयोग करने की क्या सलाह देंगे?
स्कॉट आर्किसेवस्की



1
मैंने यह सिर्फ आपके प्रदर्शन के लिए किया, बाइनरी स्ट्रिंग्स चाहते हैं, न कि मानव-रीडबेल स्ट्रिंग्स, आपकी चाबियों के लिए
स्कॉट आर्किस्जेवस्की

22

उपयोग mcrypt_encrypt()और mcrypt_decrypt()इसी मापदंडों के साथ। वास्तव में आसान और सीधे आगे, और आप एक युद्ध-परीक्षण एन्क्रिप्शन पैकेज का उपयोग करते हैं।

संपादित करें

इस उत्तर के 5 साल और 4 महीने बाद, mcryptविस्तार अब PHP से निकासी और अंतिम निष्कासन की प्रक्रिया में है।


34
लड़ाई का परीक्षण किया और 8 साल से अधिक समय तक अद्यतन नहीं किया गया?
मार्टन बोड्यूज

2
खैर, mcrypt PHP7 में है और नहीं पदावनत - यह मेरे लिए काफी अच्छा है। सभी कोड ओपनएसएसएल की भयानक गुणवत्ता के नहीं हैं और उन्हें हर कुछ दिनों में पैचिंग की आवश्यकता होती है।
यूजेन रीक

3
समर्थन के संबंध में mcrypt सिर्फ भयानक नहीं है। यह PKCS # 7 अनुरूप पैडिंग, प्रमाणित एन्क्रिप्शन जैसी सर्वोत्तम प्रथाओं को भी लागू नहीं करता है। यह SHA-3 या किसी भी अन्य नए एल्गोरिथ्म का समर्थन नहीं करेगा क्योंकि कोई भी इसे बनाए नहीं रख रहा है, आपको अपग्रेड पथ पर लूट रहा है। इसके अलावा यह आंशिक कुंजी, शून्य गद्दी प्रदर्शन आदि जैसी चीजों को स्वीकार करता था। एक अच्छा कारण है कि इसे धीरे-धीरे PHP से हटाए जाने की प्रक्रिया में है।
मैर्टन बोडेव्स

2
PHP 7.1 में, सभी mcrypt_ * फ़ंक्शंस E_DEPRECATED नोटिस उठाएंगे। PHP 7.1 + 1 (यह 7.2 या 8.0 हो) में, mcrypt एक्सटेंशन को कोर से बाहर और PECL में ले जाया जाएगा, जहां वे लोग जो वास्तव में इसे इंस्टॉल करना चाहते हैं, वे अभी भी ऐसा कर सकते हैं यदि वे PECL से PHP एक्सटेंशन इंस्टॉल कर सकते हैं।
म्लादेन जेन्जेटोविक

4

PHP 7.2 पूरी तरह से दूर चला गया Mcryptऔर एन्क्रिप्शन अब बनाए रखने योग्य Libsodiumलाइब्रेरी पर आधारित है ।

आपकी सभी एन्क्रिप्शन जरूरतों को मूल रूप से Libsodiumलाइब्रेरी के माध्यम से हल किया जा सकता है ।

// On Alice's computer:
$msg = 'This comes from Alice.';
$signed_msg = sodium_crypto_sign($msg, $secret_sign_key);


// On Bob's computer:
$original_msg = sodium_crypto_sign_open($signed_msg, $alice_sign_publickey);
if ($original_msg === false) {
    throw new Exception('Invalid signature');
} else {
    echo $original_msg; // Displays "This comes from Alice."
}

Libsodium प्रलेखन: https://github.com/paragonie/pecl-libsodium-doc


2
यदि आप कुछ कोड पेस्ट करते हैं, तो सुनिश्चित करें कि सभी चर कवर किए गए हैं। आपके उदाहरण में $ secret_sign_key और $ alice_sign_publickey NULL
अपरिभाषित

1
crypto_signएपीआई करता नहीं एन्क्रिप्ट संदेश - में से एक की आवश्यकता होगी crypto_aead_*_encryptकाम करता है।
रोजर ड्यूक

1

महत्वपूर्ण यह उत्तर केवल PHP 5 के लिए मान्य है, PHP 7 में अंतर्निहित क्रिप्टोग्राफिक कार्यों का उपयोग करें।

यहाँ सरल लेकिन पर्याप्त कार्यान्वयन सुरक्षित है:

  • CBC मोड में AES-256 एन्क्रिप्शन
  • PBKDF2 सादे पाठ पासवर्ड से एन्क्रिप्शन कुंजी बनाने के लिए
  • एन्क्रिप्टेड संदेश को प्रमाणित करने के लिए HMAC।

कोड और उदाहरण यहाँ हैं: https://stackoverflow.com/a/19445173/1387163


1
मैं एक क्रिप्टोग्राफी विशेषज्ञ नहीं हूं, लेकिन एक पासवर्ड से सीधे एक कुंजी प्राप्त करना भयानक विचार जैसा लगता है। रेनबो टेबल + कमजोर पासवर्ड और गया आपकी सुरक्षा है। इसके अलावा mcrypt फ़ंक्शन के लिए आपका लिंक पॉइंट, जो कि PHP 7.1 के बाद से हटा दिया गया है
Alph.Dev

@ Alph.Dev आप सही हैं ऊपर दिए गए उत्तर केवल PHP 5 के लिए मान्य हैं
यूजीन फिदेलिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.