इससे पहले कि आप आगे कुछ भी करें, एन्क्रिप्शन और प्रमाणीकरण के बीच के अंतर को समझने की कोशिश करें , और आप केवल एन्क्रिप्शन के बजाय प्रमाणित एन्क्रिप्शन क्यों चाहते हैं ।
प्रमाणित एन्क्रिप्शन को लागू करने के लिए, आप तब MAC एन्क्रिप्ट करना चाहते हैं। एन्क्रिप्शन और प्रमाणीकरण का क्रम बहुत महत्वपूर्ण है! इस प्रश्न के मौजूदा उत्तरों में से एक ने यह गलती की; के रूप में कई क्रिप्टोग्राफी पुस्तकालयों PHP में लिखा है।
आपको अपनी स्वयं की क्रिप्टोग्राफी को लागू करने से बचना चाहिए , और इसके बजाय क्रिप्टोग्राफी विशेषज्ञों द्वारा लिखित और समीक्षा की गई सुरक्षित लाइब्रेरी का उपयोग करना चाहिए ।
अद्यतन: PHP 7.2 अब libsodium प्रदान करता है ! सर्वोत्तम सुरक्षा के लिए, PHP 7.2 या उच्चतर का उपयोग करने के लिए अपने सिस्टम को अपडेट करें और केवल इस उत्तर में libsodium सलाह का पालन करें।
यदि आपके पास पीईसीएल पहुंच है (या सोडियम_कंपेट यदि आप पीईसीएल के बिना लिबासोडियम चाहते हैं) तो लिबासोडियम का उपयोग करें ; अन्यथा ...
डिफ्यूज़ / php-एन्क्रिप्शन का उपयोग करें ; अपनी खुद की क्रिप्टोग्राफी रोल न करें!
ऊपर लिंक किए गए दोनों पुस्तकालय आपके स्वयं के पुस्तकालयों में प्रमाणीकृत एन्क्रिप्शन को लागू करने के लिए आसान और दर्द रहित बनाते हैं।
यदि आप अभी भी अपनी क्रिप्टोग्राफी लाइब्रेरी लिखना और तैनात करना चाहते हैं, तो इंटरनेट पर हर क्रिप्टोग्राफी विशेषज्ञ के पारंपरिक ज्ञान के खिलाफ, ये कदम आपको उठाने होंगे।
एन्क्रिप्शन:
- CTR मोड में AES का उपयोग करके एन्क्रिप्ट करें। आप GCM का उपयोग भी कर सकते हैं (जो एक अलग मैक की आवश्यकता को हटा देता है)। इसके अतिरिक्त, ChaCha20 और Salsa20 ( libsodium द्वारा प्रदान किया गया ) ) धारा सिफर कर रहे हैं और विशेष मोड जरूरत नहीं है।
- जब तक आपने GCM को ऊपर नहीं चुना, तब तक आपको HMAC-SHA-256 (या, स्ट्रीम सिफर, Poly1305 के लिए - अधिकतर libsodium API आपके लिए ऐसा करते हैं) के साथ सिफरटेक्स्ट को प्रमाणित करना चाहिए। मैक को IV और साथ ही सिफरटेक्स को कवर करना चाहिए!
डिक्रिप्शन:
- जब तक Poly1305 या GCM का उपयोग नहीं किया जाता है, तब तक साइफरटेक्स्ट के मैक को पुनर्गणना करते हैं और मैक के साथ इसकी तुलना करते हैं।
hash_equals()
। यदि यह विफल रहता है, तो गर्भपात करें।
- संदेश को डिक्रिप्ट करें।
अन्य डिजाइन विचार:
- किसी भी चीज को कभी भी कंप्रेस न करें। सिफरटेक्स्ट कंप्रेसिबल नहीं है; एन्क्रिप्शन से पहले प्लेनटेक्स्ट को संपीड़ित करने से सूचना लीक हो सकती है (जैसे टीएलएस पर CRIME और BREACH)।
- सुनिश्चित करें कि आप उपयोग करते हैं
mb_strlen()
और mb_substr()
, मुद्दों '8bit'
को रोकने के लिए वर्ण सेट मोड का उपयोग कर रहे mbstring.func_overload
हैं।
- IVs को CSPRNG का उपयोग करके उत्पन्न किया जाना चाहिए ; यदि आप उपयोग कर रहे हैं
mcrypt_create_iv()
, तो उपयोग न करेंMCRYPT_RAND
!
- जब तक आप एक AEAD निर्माण का उपयोग कर रहे हैं, तब हमेशा के लिए एन्क्रिप्ट करें MAC!
bin2hex()
, base64_encode()
आदि कैश समय के माध्यम से अपने एन्क्रिप्शन कुंजी के बारे में जानकारी लीक कर सकते हैं। हो सके तो इनसे बचें।
यहां तक कि अगर आप यहां दी गई सलाह का पालन करते हैं, तो क्रिप्टोग्राफी के साथ बहुत कुछ गलत हो सकता है। हमेशा एक क्रिप्टोग्राफी विशेषज्ञ आपके कार्यान्वयन की समीक्षा करें। यदि आप अपने स्थानीय विश्वविद्यालय में क्रिप्टोग्राफी के छात्र के साथ व्यक्तिगत दोस्त बनने के लिए भाग्यशाली नहीं हैं, तो आप सलाह के लिए क्रिप्टोग्राफी स्टैक एक्सचेंज फोरम की कोशिश कर सकते हैं ।
यदि आपको अपने कार्यान्वयन के पेशेवर विश्लेषण की आवश्यकता है, तो आप हमेशा अपने PHP क्रिप्टोग्राफी कोड (प्रकटीकरण: मेरे नियोक्ता) की समीक्षा करने के लिए सुरक्षा सलाहकारों की एक प्रतिष्ठित टीम को नियुक्त कर सकते हैं ।
महत्वपूर्ण: जब एन्क्रिप्शन का उपयोग न करें
पासवर्ड एन्क्रिप्ट न करें । आपइन पासवर्ड-हैशिंग एल्गोरिदम में से एक का उपयोग करते हुए, उन्हें हैश करना चाहते हैं:
पासवर्ड भंडारण के लिए कभी भी सामान्य-उद्देश्य वाले हैश फ़ंक्शन (MD5, SHA256) का उपयोग न करें।
URL पैरामीटर्स को एन्क्रिप्ट न करें । यह काम का गलत साधन है।
Libsodium के साथ PHP स्ट्रिंग एन्क्रिप्शन का उदाहरण
यदि आप PHP <7.2 पर हैं या अन्यथा लिबासोडियम स्थापित नहीं है, तो आप उसी परिणाम को पूरा करने के लिए Sodium_compat का उपयोग कर सकते हैं (यद्यपि धीमी गति से)।
<?php
declare(strict_types=1);
/**
* Encrypt a message
*
* @param string $message - message to encrypt
* @param string $key - encryption key
* @return string
* @throws RangeException
*/
function safeEncrypt(string $message, string $key): string
{
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new RangeException('Key is not the correct size (must be 32 bytes).');
}
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = base64_encode(
$nonce.
sodium_crypto_secretbox(
$message,
$nonce,
$key
)
);
sodium_memzero($message);
sodium_memzero($key);
return $cipher;
}
/**
* Decrypt a message
*
* @param string $encrypted - message encrypted with safeEncrypt()
* @param string $key - encryption key
* @return string
* @throws Exception
*/
function safeDecrypt(string $encrypted, string $key): string
{
$decoded = base64_decode($encrypted);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plain = sodium_crypto_secretbox_open(
$ciphertext,
$nonce,
$key
);
if (!is_string($plain)) {
throw new Exception('Invalid MAC');
}
sodium_memzero($ciphertext);
sodium_memzero($key);
return $plain;
}
फिर इसका परीक्षण करने के लिए:
<?php
// This refers to the previous code block.
require "safeCrypto.php";
// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';
$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
हैलाइट - लिबसोडियम मेड ईज़ीयर
जिन परियोजनाओं पर मैं काम कर रहा हूं उनमें से एक हैलाइट नामक एक एन्क्रिप्शन लाइब्रेरी है , जिसका उद्देश्य लिबासोडियम को आसान और अधिक सहज बनाना है।
<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;
// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');
$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
अंतर्निहित क्रिप्टोग्राफी के सभी को libsodium द्वारा नियंत्रित किया जाता है।
डिफ्यूज / php-एन्क्रिप्शन के साथ उदाहरण
<?php
/**
* This requires https://github.com/defuse/php-encryption
* php composer.phar require defuse/php-encryption
*/
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;
require "vendor/autoload.php";
// Do this once then store it somehow:
$key = Key::createNewRandomKey();
$message = 'We are all living in a yellow submarine';
$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
नोट : Crypto::encrypt()
हेक्स-एन्कोडेड आउटपुट देता है।
एन्क्रिप्शन कुंजी प्रबंधन
यदि आप "पासवर्ड" का उपयोग करने के लिए ललचा रहे हैं, तो अभी रुकें। आपको एक यादृच्छिक 128-बिट एन्क्रिप्शन कुंजी की आवश्यकता है, न कि मानव यादगार पासवर्ड।
आप लंबे समय तक उपयोग के लिए एन्क्रिप्शन कुंजी स्टोर कर सकते हैं जैसे:
$storeMe = bin2hex($key);
और, मांग पर, आप इसे पुनः प्राप्त कर सकते हैं:
$key = hex2bin($storeMe);
मैं दृढ़ता से सलाह देता हूं कि किसी भी प्रकार के पासवर्ड की कुंजी (या कुंजी को प्राप्त करने के लिए) के बजाय दीर्घकालिक उपयोग के लिए एक यादृच्छिक रूप से उत्पन्न कुंजी को संग्रहीत करें।
यदि आप Defuse के पुस्तकालय का उपयोग कर रहे हैं:
"लेकिन मैं वास्तव में एक पासवर्ड का उपयोग करना चाहता हूं ।"
यह एक बुरा विचार है, लेकिन ठीक है, यहां इसे सुरक्षित तरीके से कैसे किया जाए।
सबसे पहले, एक यादृच्छिक कुंजी उत्पन्न करें और इसे एक स्थिर में संग्रहीत करें।
/**
* Replace this with your own salt!
* Use bin2hex() then add \x before every 2 hex characters, like so:
*/
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");
ध्यान दें कि आप अतिरिक्त काम जोड़ रहे हैं और कुंजी के रूप में इस स्थिरांक का उपयोग कर सकते हैं और अपने आप को बहुत सारे दिल का दर्द बचा सकते हैं!
फिर सीधे अपने पासवर्ड से एन्क्रिप्ट करने के बजाय अपने पासवर्ड से उपयुक्त एन्क्रिप्शन कुंजी प्राप्त करने के लिए PBKDF2 (जैसे कि) का उपयोग करें।
/**
* Get an AES key from a static password and a secret salt
*
* @param string $password Your weak password here
* @param int $keysize Number of bytes in encryption key
*/
function getKeyFromPassword($password, $keysize = 16)
{
return hash_pbkdf2(
'sha256',
$password,
MY_PBKDF2_SALT,
100000, // Number of iterations
$keysize,
true
);
}
केवल 16-वर्ण पासवर्ड का उपयोग न करें। आपकी एन्क्रिप्शन कुंजी हास्य रूप से टूट जाएगी।