PHP yüklemelerinde ortak iki yönlü şifreleme yapmanın en basit yolu nedir?
Verileri bir dize anahtarıyla şifreleyebilmem ve diğer ucunda şifresini çözmek için aynı anahtarı kullanmam gerekiyor.
Güvenlik, kodun taşınabilirliği kadar büyük bir sorun değil, bu yüzden işleri olabildiğince basit tutabilmek istiyorum. Şu anda bir RC4 uygulaması kullanıyorum, ancak yerel olarak desteklenen bir şey bulabilirsem, çok fazla gereksiz kod kaydedebileceğimi düşünüyorum.
düzenlenmiştir:
Gerçekten kullanıyor olmalısın openssl_encrypt () & openssl_decrypt ()
Scott 'in dediği gibi, Mcrypt 2007'den beri güncellenmediği için iyi bir fikir değil.
Mcrypt'u PHP - https://wiki.php.net/rfc/mcrypt-viking-funeral dan kaldırmak için bir RFC bile var.
Önemli : Bir çok özel bir kullanım durumunuz yoksa, şifreleri şifrelemeyin , kullan bunun yerine şifre şifreleme algoritması. Birisi bir sunucu tarafı uygulamasında şifrele şifrelerini söylediğinde, ya bilgisiz ya da tehlikeli bir sistem tasarımını tarif ediyorlar. Şifreleri güvenle saklayın şifrelemeden tamamen ayrı bir sorundur.
Haberdar olmak. Güvenli sistemler tasarlayın.
PHP 5.4 veya daha yenisi kullanıyorsanız ve kendiniz bir şifreleme modülü yazmak istemiyorsanız, kimliği doğrulanmış şifreleme sağlayan bir kütüphane kullanmanızı öneririz. Bağlantılı olduğum kütüphane sadece PHP 'in sağladığı ve bir avuç güvenlik araştırmacısı tarafından periyodik olarak gözden geçirilenlere dayanıyor. (Ben dahil.)
Taşınabilirlik hedefleriniz PECL uzantıları gerektirmesini engellemezse, libsodium sizin için kesinlikle önerilir. veya PHP ile yazabilirim.
Güncelleme (2016-06-12): Artık sodium_compat kullanabilir ve PECL uzantıları yüklemeden aynı kripto libsodium tekliflerini kullanabilirsiniz. .
Elinizi kriptografi mühendisliğinde denemek istiyorsanız, okumaya devam edin.
İlk önce, öğrenmek için zaman ayırmalısınız doğrulanmamış şifrelemenin tehlikeleri ve Kriptografik Doom Prensibi .
PHP içindeki şifreleme aslında basittir (bilgilerinizi nasıl şifreleyeceğinizle ilgili bazı kararlar verdikten sonra --- kullanacağız openssl_encrypt()
ve openssl_decrypt()
kullanacağız. Sisteminizde desteklenen yöntemlerin bir listesi için openssl_get_cipher_methods()
.En iyi seçenek TO modunda AES :
aes-128-ctr
aes-192-ctr
aes-256-ctr
Şu anda AES anahtar büyüklüğü 'nin endişe edilecek önemli bir konu olduğuna inanmak için hiçbir neden yoktur (256’daki kötü anahtar programlaması nedeniyle muhtemelen daha büyüktür değil daha iyidir. bit modu).
Not: mcrypt
kullanmıyoruz çünkü abandonware ve --- yamalanmamış hatalar = güvenliği etkileyen olabilir. Bu nedenlerden dolayı, diğer PHP geliştiricilerini de bundan kaçınmaları için teşvik ediyorum.
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);
Demo : https://3v4l.org/jl7qR
Yukarıdaki basit kripto kütüphanesinin kullanımı hala güvenli değildir. Yapmamız gereken şifreleri doğrulamak ve şifresini çözmeden önce onları doğrulamak .
Not : Varsayılan olarak, UnsafeCrypto::encrypt()
, ham bir ikili dize döndürür. İkili güvenlikli bir formatta (base64 kodlu) saklamanız gerekirse, bu şekilde arayın:
$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);
Demo : http://3v4l.org/f5K9
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);
Demolar : ham ikili , base64 kodl
Herhangi biri bu SaferCrypto
kitaplığını üretim ortamında kullanmak veya aynı kavramları sizin kendi uygulamanızda kullanmak isterse, bunu yapmadan önce ikinci bir görüş için yerleşik şifreleyicileriniz 'e ulaşmanızı şiddetle tavsiye ederim. Farkında bile olamayacağım hataları hakkında size bilgi verebilirler.
saygın bir kriptografi kütüphanesi kullanarak çok daha iyi olacaksınız.
İlgili parametrelerle mcrypt_encrypt()
ve mcrypt_decrypt()
kullanın. Gerçekten kolay ve yalındır ve savaşta test edilmiş bir şifreleme paketi kullanıyorsunuz.
DÜZENLE
Bu cevaptan 5 yıl 4 ay sonra mcrypt
eklentisi artık kullanımdan kaldırıldı ve PHP'den çıkarıldı.
PHP 7.2 tamamen Mcrypt
'den uzaklaştı ve şimdi şifreleme, bakımlanabilir Libsodium
kütüphanesini temel alıyor.
Tüm şifreleme ihtiyaçlarınız temel olarak Libsodium
kütüphanesi aracılığıyla çözülebilir.
// 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 belgeleri: https://github.com/paragonie/pecl-libsodium-doc
İşte basit ama yeterince güvenli uygulama:
Kod ve örnekler burada: https://stackoverflow.com/a/19445173/138716