web-gelistirme-sc.com

PHP kullanarak en basit iki yönlü şifreleme

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.

206
user1206970

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.

180
472084

Ö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'de Taşınabilir Veri Şifreleme

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 .

  • Şifrelenmiş veriler hala kötü niyetli bir kullanıcı tarafından değiştirilebilmektedir.
  • Şifreli verilerin kimliğini doğrulamak, kurcalanmayı önler.
  • Şifrelenmemiş verilerin kimliğini doğrulamak, kurcalanmayı engellemez.

Şifreleme ve Şifre Çözme

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.

OpenSSL kullanarak basit şifreleme/şifre çözme ambalajı

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

Kullanım Örneği

$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

Basit Kimlik Doğrulama Paketleyici

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

Kullanım Örneği

$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.

207

İ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ı.

22
Eugen Rieck

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

4
Hemerson Varela

İşte basit ama yeterince güvenli uygulama:

  • CBC modunda AES-256 şifreleme
  • PBKDF2 düz metin şifresiz şifreleme anahtarı oluşturmak için
  • Şifreli iletinin kimliğini doğrulamak için HMAC.

Kod ve örnekler burada: https://stackoverflow.com/a/19445173/138716

2
Eugene Fidelin