it-swarm-tr.com

Bir PHP Dizesini Nasıl Şifrele ve Şifresini Çöz

Demek istediğim ... dir:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

Belki bir şey gibi:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • PHP'de bunu nasıl yapabilirsiniz?

Crypt_Blowfish Kullanılmaya çalışıldı, fakat benim için işe yaramadı.

197
夏期劇場

Ne yapılmamalı

UYARI:
Bu cevapta ECB kullanılıyor. ECB bir şifreleme modu değil, sadece bir yapı taşı. Bu yanıtta gösterildiği gibi ECB'yi kullanmak, dizeyi güvenli bir şekilde şifrelemez. ECB'yi kodunuzda kullanmayın. İyi bir çözüm için bakınız Scott'ın cevabı .

Kendim aldım. Aslında google'da bir cevap buldum ve bir şeyleri değiştirdim. Ancak sonuç tamamen güvensiz.

<?php
define("ENCRYPTION_KEY", "[email protected]#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_Rand);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_Rand);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>
44
夏期劇場

Daha fazla bir şey yapmadan önce, şifreleme ve kimlik doğrulama ve neden muhtemelen doğrulanmış şifreleme yerine sadece şifreleme isteyeceksiniz.

Kimliği doğrulanmış şifrelemeyi uygulamak için, daha sonra MAC şifrelemek istiyorsunuz. Şifreleme ve kimlik doğrulama sırası çok önemlidir! Bu sorunun mevcut cevaplarından biri bu hatayı yaptı; PHP ile yazılmış birçok şifreleme kütüphanesinin yaptığı gibi.

Yapmanız gereken kendi şifrelemenizi uygulamaktan kaçının ve bunun yerine şifreleme uzmanları tarafından yazılan ve incelenen güvenli bir kütüphane kullanmalısınız.

Güncelleme: PHP 7.2 şimdi libsodium sunuyor! En iyi güvenlik için, sistemlerinizi PHP 7.2 veya daha yenisini kullanacak şekilde güncelleyin ve yalnızca bu yanıttaki libsodium tavsiyelerini izleyin.

PECL erişiminiz varsa libsodium kullanın (veya sodyum_compat PECL'siz libsodium istiyorsanız); Aksi ...
Defuse/php-encryption kullanın ; kendi şifrelemeni yuvarlama!

Yukarıda bağlanan kitaplıkların her ikisi de, kendi kitaplıklarınıza doğrulanmış şifreleme uygulamanızı kolay ve acısız hale getirir.

İnternetteki her kriptografi uzmanının geleneksel bilgeliğine karşı kendi kriptografi kitaplığınızı yazmaya ve dağıtmaya devam etmek istiyorsanız, atmanız gereken adımlar bunlar.

Şifreleme:

  1. TO modunda AES kullanarak şifreleyin. GCM'yi de kullanabilirsiniz (ayrı bir MAC ihtiyacını ortadan kaldırır). Ek olarak, ChaCha20 ve Salsa20 ( libsodium tarafından sağlanmıştır) akış şifrelerdir ve özel modlara ihtiyaç duymazlar.
  2. Yukarıda GCM'yi seçmediyseniz, şifreli metni HMAC-SHA-256 ile doğrulamanız gerekir (veya akış şifreleri için Poly1305 - çoğu libsodium API'si bunu sizin için yapar). MAC, IV kodunun yanı sıra şifreli metni de kapsamalıdır!

Şifre çözme:

  1. Poly1305 veya GCM kullanılmadığı sürece, şifreli metnin MAC'ini yeniden hesaplayın ve hash_equals() kullanılarak gönderilen MAC ile karşılaştırın. Başarısız olursa, iptal edin.
  2. Mesajın şifresini çözün.

Diğer Tasarım Düşünceleri:

  1. Hiçbir şeyi sıkıştırmayın. Şifreli metin sıkıştırılamaz; şifrelemeden önce düz metin sıkıştırmak bilgi sızıntılarına yol açabilir (örneğin, TLS'deki CRIME ve BREACH).
  2. '8bit' sorunlarını önlemek için mbstring.func_overload karakter kümesi modunu kullanarak mb_strlen() ve mb_substr() kullandığınızdan emin olun.
  3. IV'ler bir CSPRNG ; mcrypt_create_iv() kullanıyorsanız, MCRYPT_Rand KULLANMAYIN!
  4. Bir AEAD yapısı kullanmıyorsanız, ( HER ZAMAN MAC sonra şifreleyin!
  5. bin2hex(), base64_encode() vb., şifreleme anahtarlarınızla ilgili bilgileri önbellek zamanlaması yoluyla sızdırabilir. Mümkünse bunlardan kaçının.

Burada verilen tavsiyelere uysanız bile, kriptografi ile ilgili birçok sorun olabilir. Uygulamanızı her zaman bir şifreleme uzmanına gözden geçirin. Yerel üniversitenizde bir şifreleme öğrencisi ile kişisel arkadaş olabileceğiniz için yeterince şanslı değilseniz, her zaman deneyebilirsiniz. Cryptography Stack Exchange tavsiye için forum.

Uygulamanızın profesyonel bir analizine ihtiyacınız varsa, her zaman bir PHP şifreleme kodunuzu incelemek için saygın bir güvenlik danışmanı ekibi (açıklama: işverenim) kiralayabilirsiniz.

Önemli: Şifrelemenin Ne Zaman Kullanılmayacağı

Yapmayın şifreleyin şifreler. Bu şifre karma algoritmalarından birini kullanarak, bunun yerine hash komutunu istiyorsanız:

Parola depolaması için asla genel amaçlı bir karma işlevi (MD5, SHA256) kullanmayın.

RL Parametrelerini şifrelemeyin . İş için yanlış bir araçtır.

Libsodium ile PHP Dize Şifreleme Örneği

PHP <7.2 üzerindeyseniz ya da libsodium kurulu değilse, aynı sonucu elde etmek için (yavaş olsa da) sodyum_compat kullanabilirsiniz.

<?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;
}

Sonra test etmek için:

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

Halite - Libsodium Kolaylaştırıldı

Üzerinde çalıştığım projelerden biri, libsodium'u daha kolay ve sezgisel hale getirmeyi amaçlayan Halite adlı bir şifreleme kütüphanesi.

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

Temel şifrelemenin tümü libsodium tarafından gerçekleştirilir.

Defuse/php şifreleme örneği

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

Not : Crypto::encrypt(), altıgen kodlanmış çıktı döndürür.

Şifreleme Anahtarı Yönetimi

Bir "şifre" kullanmaya istekliyseniz, hemen durun. Rastgele bir 128 bit şifreleme anahtarına ihtiyacınız var, unutulmaz bir şifre değil.

Bu gibi uzun süreli kullanım için bir şifreleme anahtarı saklayabilirsiniz:

$storeMe = bin2hex($key);

Ve talep üzerine, şu şekilde alabilirsiniz:

$key = hex2bin($storeMe);

I kuvvetle yalnızca anahtar olarak herhangi bir parola yerine uzun süreli kullanım için rastgele oluşturulmuş bir anahtar saklamanızı (veya anahtarı türetmenizi) önerir.

Defuse'un kütüphanesini kullanıyorsanız:

"Ama ben gerçekten bir şifre kullanmak istiyorum."

Bu kötü bir fikir, ama tamam, işte güvenle yapılıyor.

İlk önce rastgele bir anahtar oluşturun ve bunu sabit bir yerde saklayın.

/**
 * 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");

Fazladan bir çalışma ekleyebileceğinizi ve bu sabitin sadece anahtar olarak kullanabileceğini ve kendinize gönül rahatlığı yaşayabileceğinizi unutmayın!

Ardından, doğrudan şifrenizle şifrelemek yerine şifrenizden uygun bir şifreleme anahtarı türetmek için PBKDF2 kullanın (bu şekilde).

/**
 * 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
    );
}

Sadece 16 karakterlik bir şifre kullanmayın. Şifreleme anahtarınız komik bir şekilde kırılacak.

367

Partiye geç kaldım, ancak bunu yapmanın doğru yolunu aradım. Bu sayfaya rastladım, Google arama sonuçlarının en iyilerinden biriydi. Bu nedenle, görüşümü, sorun olarak düşündüğümü paylaşmak istiyorum. Bu yazının yazıldığı tarihte (2017'nin başında). PHP 7.1.0'dan mcrypt_decrypt ve mcrypt_encrypt kullanımdan kaldırılacak, bu nedenle gelecekteki kanıt kodunu oluşturmak openssl_encrypt ve openssl_decrypt kullanmalıdır.

Gibi bir şey yapabilirsiniz:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

Önemli : Bu, güvenli olmayan (ECB mod ) kullanır. Kriptografi mühendisliğinde çarpışma kursu almadan basit bir çözüm istiyorsanız, kendiniz yazmayın, sadece bir kütüphane kullanın .

Güvenlik ihtiyacınıza bağlı olarak, diğer tüm chipper yöntemlerini de kullanabilirsiniz. Mevcut chipper yöntemlerini bulmak için lütfen openssl_get_cipher_methods işlevine bakın.

50
Emil Borconi

Laravel framework için

Laravel framework kullanıyorsanız, dahili işlevlerle şifrelemek ve şifresini çözmek daha kolaydır.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

Not: config/app.php dosyasının anahtar seçeneğinde 16, 24 veya 32 karakter rasgele bir dize ayarladığınızdan emin olun. Aksi takdirde, şifreli değerler güvenli olmaz.

12
Somnath Muluk

Tarihsel Not: Bu PHP4 zamanında yazılmıştır. Şimdi buna "eski kod" diyoruz.

Bu cevabı tarihsel amaçlar için bıraktım - ancak yöntemlerden bazıları artık kullanımdan kaldırıldı, DES şifreleme yöntemi önerilen bir uygulama değil.

Bu kodu iki nedenden dolayı güncellemedim: 1) PHP'de elle şifreleme yöntemleriyle çalışmıyorum ve 2) bu kod hala amaçlandığı amaca hizmet ediyor: şifrelemenin nasıl çalışabileceğine ilişkin asgari, basit konsept göstermek PHP’de.

Benzer bir şekilde basit bulursanız, insanların 10-20 kod satırında veya daha az kodda başlatılmasını sağlayabilecek "aptallar için PHP şifrelemesi" türünden bir kaynak bulursanız, yorumlarda bana bildirin.

Bunun ötesinde, lütfen bu erken dönem PHP4 minimalist şifreleme yanıtının Klasik Bölümünün tadını çıkarın.


İdeal olarak, mcrypt PHP kütüphanesine, kesinlikle popüler ve çok çeşitli görevler olduğu için erişim hakkınız vardır. İşte farklı şifreleme türleri ve bazı örnek kodların bir listesi: PHP'de Şifreleme Teknikleri

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

Birkaç uyarı:

1) Tek yönlü bir işlem yapacağı zaman asla tersinir veya "simetrik" şifreleme kullanmayın.

2) Veriler gerçekten hassassa, kredi kartı veya sosyal güvenlik numaraları gibi; basit bir kod yığınının sağlayacağından daha fazlasına ihtiyacınız var, fakat bunun yerine, bu amaç için tasarlanmış bir kripto kütüphanesine ve gerekli yöntemleri araştırmak için önemli bir zamana ihtiyacınız var. Ayrıca, yazılım şifrelemesi muhtemelen hassas verilerin güvenliğinin <% 10'udur. Bir nükleer santrali yeniden kablolamak gibi bir şey - görevin tehlikeli ve zor olduğunu ve bu durumda sizin bilginizin ötesinde olduğunu kabul edin. Mali cezalar çok büyük olabilir, bu yüzden bir hizmet kullanmak ve onlara sorumluluk vermek daha iyidir.

3) Burada listelendiği gibi kolayca uygulanabilen her türlü şifreleme, yanlışlıkla/kasıtlı sızıntı durumunda meraklı gözlerden uzak tutmak veya maruz kalmayı sınırlandırmak istediğiniz önemli ölçüde önemli bilgileri makul şekilde koruyabilir. Ancak anahtarın web sunucusunda düz metin olarak nasıl saklandığını görünce, verileri alabilirlerse şifre çözme anahtarını alabilirler.

Olabilir, eğlenin :)

6
BrianH

Kütüphane kullanmak istemiyorsanız (ki yapmanız gereken), bunun gibi bir şey kullanın (PHP 7):

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);
3
Ascon

Kodun altındaki özel karakterli tüm dizeler için php olarak çalışın

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
0
Javed

Güncellenmiş

PHP 7 hazır sürümü. PHP OpenSSL Kütüphanesinden gelen openssl_encrypt işlevini kullanır .

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&[email protected]$&*[email protected]#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);
0
夏期劇場