it-swarm-id.com

Bagaimana Anda Mengenkripsi dan Mendekripsi String PHP?

Yang saya maksud:

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

Mungkin sesuatu seperti:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • Di PHP, bagaimana Anda bisa melakukan ini?

Mencoba menggunakan Crypt_Blowfish, tetapi tidak berhasil untuk saya.

197
夏期劇場

Apa yang tidak boleh dilakukan

PERINGATAN:
Jawaban ini menggunakan ECB . ECB bukan mode enkripsi, ini hanya blok bangunan. Menggunakan ECB seperti yang ditunjukkan dalam jawaban ini sebenarnya tidak mengenkripsi string dengan aman. Jangan gunakan ECB dalam kode Anda. Lihat jawaban Scott untuk solusi yang baik.

Saya mengerti sendiri. Sebenarnya saya menemukan beberapa jawaban di google dan baru saja memodifikasi sesuatu. Hasilnya benar-benar tidak aman.

<?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
夏期劇場

Sebelum Anda melakukan sesuatu lebih jauh, cobalah untuk memahami perbedaan antara enkripsi dan otentikasi , dan mengapa Anda mungkin menginginkan enkripsi terotentikasi daripada hanya enkripsi .

Untuk menerapkan enkripsi yang diautentikasi, Anda ingin Mengenkripsi kemudian MAC. rutan enkripsi dan otentikasi sangat penting! Salah satu jawaban yang ada untuk pertanyaan ini membuat kesalahan ini; seperti halnya banyak pustaka kriptografi yang ditulis dalam PHP.

Anda harus menghindari menerapkan kriptografi Anda sendiri , dan alih-alih menggunakan perpustakaan aman yang ditulis oleh dan ditinjau oleh para ahli kriptografi.

Pembaruan: PHP 7.2 sekarang menyediakan libsodium ! Untuk keamanan terbaik, perbarui sistem Anda untuk menggunakan PHP 7.2 atau lebih tinggi dan hanya mengikuti saran libsodium dalam jawaban ini.

Gunakan libsodium jika Anda memiliki akses PECL (atau sodium_compat jika Anda ingin libsodium tanpa PECL); jika tidak ...
Gunakan defuse/php-enkripsi ; jangan gulung kriptografi Anda sendiri!

Kedua perpustakaan yang ditautkan di atas membuatnya mudah dan tidak menyakitkan untuk menerapkan enkripsi terotentikasi ke perpustakaan Anda sendiri.

Jika Anda masih ingin menulis dan menggunakan pustaka kriptografi Anda sendiri, bertentangan dengan kebijaksanaan konvensional setiap ahli kriptografi di Internet, ini adalah langkah-langkah yang harus Anda ambil.

Enkripsi:

  1. Enkripsi menggunakan AES dalam mode CTR. Anda juga dapat menggunakan GCM (yang menghilangkan kebutuhan untuk MAC yang terpisah). Selain itu, ChaCha20 dan Salsa20 (disediakan oleh libsodium ) adalah stream cipher dan tidak memerlukan mode khusus.
  2. Kecuali Anda memilih GCM di atas, Anda harus mengotentikasi ciphertext dengan HMAC-SHA-256 (atau, untuk stream cipher, Poly1305 - kebanyakan libsodium API melakukan ini untuk Anda). MAC harus mencakup IV serta ciphertext!

Dekripsi:

  1. Kecuali jika Poly1305 atau GCM digunakan, hitung ulang MAC dari ciphertext dan bandingkan dengan MAC yang dikirim menggunakan hash_equals() . Jika gagal, batalkan.
  2. Dekripsi pesan tersebut.

Pertimbangan Desain Lainnya:

  1. Jangan kompres apa pun. Ciphertext tidak bisa dimampatkan; mengompresi plaintext sebelum enkripsi dapat menyebabkan kebocoran informasi (mis., CRIME dan BREACH di TLS).
  2. Pastikan Anda menggunakan mb_strlen() dan mb_substr(), menggunakan mode set karakter '8bit' untuk mencegah masalah mbstring.func_overload.
  3. IVs harus menghasilkan menggunakan CSPRNG ; Jika Anda menggunakan mcrypt_create_iv(), JANGAN GUNAKAN MCRYPT_Rand!
  4. Kecuali Anda menggunakan konstruk AEAD, SELALU mengenkripsi MAC!
  5. bin2hex(), base64_encode(), dll. dapat membocorkan informasi tentang kunci enkripsi Anda melalui waktu cache. Hindari mereka jika memungkinkan.

Bahkan jika Anda mengikuti saran yang diberikan di sini, banyak yang bisa salah dengan kriptografi. Selalu minta pakar kriptografi untuk meninjau implementasi Anda. Jika Anda tidak cukup beruntung untuk menjadi teman pribadi dengan siswa kriptografi di universitas setempat, Anda selalu dapat mencoba forum Cryptography Stack Exchange untuk saran.

Jika Anda memerlukan analisis profesional tentang implementasi Anda, Anda selalu dapat menyewa tim konsultan keamanan yang memiliki reputasi baik untuk meninjau PHP kode kriptografi Anda (pengungkapan: perusahaan saya).

Penting: Kapan Tidak Menggunakan Enkripsi

Jangan mengenkripsi kata sandi. Anda ingin hash sebagai gantinya, menggunakan salah satu dari algoritma hashing kata sandi ini:

Jangan pernah menggunakan fungsi hash tujuan umum (MD5, SHA256) untuk penyimpanan kata sandi.

Jangan mengenkripsi Parameter URL . Ini adalah alat yang salah untuk pekerjaan itu.

Contoh Enkripsi String PHP dengan Libsodium

Jika Anda menggunakan PHP <7.2 atau tidak menginstal libsodium, Anda dapat menggunakan sodium_compat untuk mencapai hasil yang sama (walaupun lebih lambat).

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

Kemudian untuk mengujinya:

<?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 Membuat Lebih Mudah

Salah satu proyek yang saya kerjakan adalah perpustakaan enkripsi bernama Halite , yang bertujuan untuk membuat libsodium lebih mudah dan lebih intuitif.

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

Semua kriptografi yang mendasarinya ditangani oleh libsodium.

Contoh dengan defuse/php-enkripsi

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

Catatan : Crypto::encrypt() mengembalikan output hex-encoded.

Manajemen Kunci Enkripsi

Jika Anda tergoda untuk menggunakan "kata sandi", berhentilah sekarang. Anda memerlukan kunci enkripsi 128-bit acak, bukan kata sandi yang mudah diingat manusia.

Anda dapat menyimpan kunci enkripsi untuk penggunaan jangka panjang seperti:

$storeMe = bin2hex($key);

Dan, sesuai permintaan, Anda dapat mengambilnya seperti ini:

$key = hex2bin($storeMe);

Saya sangat merekomendasikan hanya menyimpan kunci yang dibuat secara acak untuk penggunaan jangka panjang alih-alih segala jenis kata sandi sebagai kunci (atau untuk menurunkan kunci).

Jika Anda menggunakan perpustakaan Defuse:

"Tapi saya benar-benar ingin menggunakan kata sandi."

Itu ide yang buruk, tapi oke, inilah cara melakukannya dengan aman.

Pertama, buat kunci acak dan simpan dalam konstanta.

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

Perhatikan bahwa Anda menambahkan pekerjaan ekstra dan bisa menggunakan konstanta ini sebagai kuncinya dan menyelamatkan diri Anda dari sakit hati!

Kemudian gunakan PBKDF2 (seperti itu) untuk mendapatkan kunci enkripsi yang sesuai dari kata sandi Anda daripada langsung mengenkripsi dengan kata sandi Anda.

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

Jangan hanya menggunakan kata sandi 16 karakter. Kunci enkripsi Anda akan rusak secara komikal.

367

Saya terlambat ke pesta, tetapi mencari cara yang benar untuk melakukannya saya menemukan halaman ini adalah salah satu pengembalian pencarian Google teratas, jadi saya ingin berbagi pandangan saya tentang masalah tersebut, yang saya anggap sebagai up to date pada saat penulisan posting ini (awal 2017). Dari PHP 7.1.0 mcrypt_decrypt dan mcrypt_encrypt akan ditinggalkan, jadi membangun kode bukti masa depan harus menggunakan openssl_encrypt dan openssl_decrypt

Anda dapat melakukan sesuatu seperti:

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

Penting : Ini menggunakan mode ECB , yang tidak aman. Jika Anda menginginkan solusi sederhana tanpa mengambil kursus kilat dalam rekayasa kriptografi, jangan tulis sendiri, hanya gunakan perpustakaan .

Anda dapat menggunakan metode chipper lainnya juga, tergantung pada kebutuhan keamanan Anda. Untuk mengetahui metode chipper yang tersedia silakan lihat fungsi openssl_get_cipher_methods .

50
Emil Borconi

Untuk kerangka kerja Laravel

Jika Anda menggunakan kerangka Laravel maka lebih mudah untuk mengenkripsi dan mendekripsi dengan fungsi internal.

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

Catatan: Pastikan untuk mengatur string acak 16, 24, atau 32 dalam opsi kunci file config/app.php. Jika tidak, nilai yang dienkripsi tidak akan aman.

12
Somnath Muluk

Catatan Sejarah: Ini ditulis pada saat PHP4. Inilah yang kami sebut "kode warisan" sekarang.

Saya telah meninggalkan jawaban ini untuk tujuan historis - tetapi beberapa metode sekarang sudah usang, DES metode enkripsi bukan praktik yang disarankan, dll.

Saya belum memperbarui kode ini karena dua alasan: 1) Saya tidak lagi bekerja dengan metode enkripsi dengan tangan di PHP, dan 2) kode ini masih melayani tujuan yang dimaksudkan: untuk menunjukkan konsep minimum dan sederhana tentang bagaimana enkripsi dapat bekerja dalam PHP.

Jika Anda menemukan sumber yang serupa, "Enkripsi PHP untuk boneka" yang dapat membuat orang mulai dengan 10-20 baris kode atau kurang, beri tahu saya dalam komentar.

Selain itu, silakan nikmati Episode Klasik ini dari jawaban enkripsi minimalis PHP4 era awal.


Idealnya Anda memiliki - atau bisa mendapatkan - akses ke perpustakaan mcrypt PHP, karena beragam tugas yang sangat populer dan sangat berguna. Berikut ini adalah beberapa jenis enkripsi dan contoh kode: Teknik Enkripsi dalam PHP

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

Beberapa peringatan:

1) Jangan pernah menggunakan enkripsi reversibel, atau "simetris" ketika hash satu arah akan dilakukan.

2) Jika data benar-benar sensitif, seperti kartu kredit atau nomor jaminan sosial, hentikan; Anda membutuhkan lebih dari yang bisa diberikan oleh sepotong kode sederhana, tetapi Anda membutuhkan pustaka crypto yang dirancang untuk tujuan ini dan banyak waktu untuk meneliti metode yang diperlukan. Selanjutnya, perangkat lunak crypto mungkin <10% dari keamanan data sensitif. Ini seperti membuat ulang stasiun tenaga nuklir - menerima bahwa tugas itu berbahaya dan sulit dan di luar pengetahuan Anda jika itu masalahnya. Hukuman finansial bisa sangat besar, jadi lebih baik menggunakan layanan dan mengirimkan tanggung jawab kepada mereka.

3) Segala jenis enkripsi yang mudah diimplementasikan, seperti yang tercantum di sini, dapat secara wajar melindungi informasi yang agak penting yang ingin Anda jaga agar tidak terbelalak atau membatasi paparan jika terjadi kebocoran yang tidak disengaja/disengaja. Tetapi melihat bagaimana kunci disimpan dalam teks biasa di server web, jika mereka bisa mendapatkan data mereka bisa mendapatkan kunci dekripsi.

Namun, bersenang-senanglah :)

6
BrianH

Jika Anda tidak ingin menggunakan pustaka (yang harus Anda) maka gunakan sesuatu seperti ini (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