Bagaimana Anda Mengenkripsi dan Mendekripsi String PHP?

225

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.

夏 期 劇場
sumber
35
@ Roger Dia tidak ingin hash, dia ingin enkripsi simetris (seperti AES), dia tidak tahu apa namanya. (Dan sekarang dia lakukan :))
Patashu
seberapa aman itu perlu?
3
@ 夏 期 劇場, Anda tidak 'garam' enkripsi simetris, Anda menggunakan kunci. Kunci harus dirahasiakan. Garam dapat dipublikasikan tanpa merusak keamanan (asalkan garam semua orang berbeda), dan ini adalah istilah yang digunakan untuk hashing password.
Patashu
2
Anda memerlukan Garam (kunci pribadi), kunci publik dan algoritma enkripsi seperti AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy
8
@CristianFlorea Penulis posting blog itu menggunakan istilah yang sama sekali tidak masuk akal dalam konteks enkripsi simetris. Tidak ada kunci publik dengan AES, juga tidak ada garam. Ada satu kunci; itu harus dirahasiakan. Dalam beberapa mode operasi ada IV yang tidak perlu dirahasiakan, tetapi IV bukan garam (tergantung mode, ia dapat memiliki persyaratan yang sangat berbeda) dan tidak perlu rahasia, sedangkan kunci enkripsi yang sebenarnya sama sekali tidak dapat umum. Kunci publik / pribadi berlaku untuk kripto asimetris, tetapi tidak ada hubungannya dengan AES.
cpast

Jawaban:

410

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

Untuk menerapkan enkripsi yang diautentikasi, Anda ingin Mengenkripsi kemudian MAC. Urutan 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 penerapan kriptografi Anda sendiri , dan sebagai gantinya 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 roll 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 dan juga 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 (misalnya, CRIME dan BREACH pada TLS).
  2. Pastikan Anda menggunakan mb_strlen()dan mb_substr(), menggunakan '8bit'mode set karakter untuk mencegah mbstring.func_overloadmasalah.
  3. IVs harus menghasilkan menggunakan CSPRNG ; Jika Anda menggunakan mcrypt_create_iv(), JANGAN GUNAKANMCRYPT_RAND !
  4. Kecuali Anda menggunakan konstruk AEAD, SELALU mengenkripsi kemudian 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 meninjau penerapan Anda. Jika Anda tidak cukup beruntung untuk menjadi teman pribadi dengan seorang siswa kriptografi di universitas lokal Anda, Anda selalu dapat mencoba Cryptography Stack Exchange untuk meminta saran.

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

Penting: Kapan Tidak Menggunakan Enkripsi

Jangan mengenkripsi kata sandi . Anda ingin menggunakan 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 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 menyarankan hanya menyimpan kunci yang dibuat secara acak untuk penggunaan jangka panjang dan bukan jenis kata sandi sebagai kunci (atau untuk menurunkan kunci).

Jika Anda menggunakan perpustakaan Defuse:

"Tapi aku 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.

Scott Arciszewski
sumber
3
Jangan mengenkripsi kata sandi , hash dengan password_hash()dan periksa dengan password_verify().
Scott Arciszewski
2
"Jangan kompres apa pun." Maksud Anda seperti HTTP, spdy dan protokol lain lakukan? Sebelum TLS? Nasihat absolut banyak?
Tiberiu-Ionuț Stan
1
@ScottArciszewski Saya suka komentar Anda tentang kunci "// Lakukan ini sekali kemudian simpan entah bagaimana:" .. entah bagaimana, lol :)) baik bagaimana menyimpan 'kunci' ini (yang merupakan objek) sebagai string biasa, hardcoded? Saya membutuhkan kunci itu sendiri, sebagai string. Bisakah saya mendapatkannya dari objek ini? Terima kasih
Andrew
2
Thx, saya baru saja memodifikasi satu baris untuk membuat contoh natrium Anda bekerja:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey Ozerov
1
Wow! +1 untuk menyebutkan tidak mengenkripsi parameter URL. Saya sangat menyukai artikel yang Anda berikan: paragonie.com/blog/2015/09/...
Lynnell Emmanuel Neri
73

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 ini, yang saya anggap sebagai up to date pada saat penulisan posting ini (awal 2017). Dari PHP 7.1.0 mcrypt_decryptdan mcrypt_encryptakan 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 menulis sendiri, cukup 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 .

Emil Borconi
sumber
10
Terima kasih, saya terkejut jawaban sederhana dan jelas ini tidak lebih dipilih. Saya lebih suka tidak membaca diskusi 10 halaman tentang masalah seperti jawaban atas ketika semua yang saya inginkan adalah mengenkripsi / mendekripsi string sederhana.
laurent
4
Ini bukan jawaban yang aman. Mode ECB seharusnya tidak digunakan. Jika Anda menginginkan "jawaban yang sederhana dan jelas", cukup gunakan perpustakaan .
Scott Arciszewski
2
@ScottArciszewski, ya saya akui saya sudah bicara terlalu cepat sambil mencari beberapa kode sederhana. Sejak itu saya telah menambahkan IV dan menggunakan CBC dalam kode saya sendiri, yang cukup baik untuk saya gunakan.
laurent
Baca ini dan pertimbangkan kembali . Dengan mode CBC, penyerang dapat sepenuhnya mengubah pesan. Jika pesan adalah file, penyerang dapat membalik bit dan pop calc.exe. Risiko enkripsi yang tidak diautentikasi sangat berat.
Scott Arciszewski
7
Itu semua tergantung pada use case! Ada kasus-kasus di mana ini sempurna HALUS. Misalnya saya ingin meneruskan parameter GET dari halaman ke halaman, katakanlah prod_id=123tetapi saya hanya tidak ingin membuat 123 dapat dibaca untuk semua orang, namun meskipun mereka bisa membacanya, itu tidak akan menjadi masalah. Penyerang yang bisa mengganti 123 ke nilai kustom tidak akan menyebabkan kerugian, ia hanya akan bisa mendapatkan detail dari produk lain, tetapi Joe Average User tidak akan memiliki petunjuk tentang cara mendapatkan detail untuk produk 124 misalnya. Untuk skenario seperti ini, ini adalah solusi sempurna, untuk keamanan itu tidak jalan!
Emil Borconi
43

Apa yang tidak 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. Namun hasilnya benar-benar tidak aman.

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$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;
}
?>
夏 期 劇場
sumber
8
Anda dapat menggunakan "MCRYPT_MODE_CBC" sebagai ganti "MCRYPT_MODE_ECB" untuk memastikan keamanan yang lebih baik.
Parixit
10
Ramesh, ini karena Anda mendapatkan data terenkripsi yang mentah. Anda bisa mendapatkan versi terenkripsi dari data yang lebih baik dengan menggunakan base64, seperti ini: base64_encode(encrypt($string))- Untuk mendekripsi:decrypt(base64_decode($encrypted))
mendezcode
82
PERINGATAN: ini tidak aman . Mode ECB tidak boleh digunakan untuk string, ECB tidak mengambil IV, ini tidak diautentikasi, ia menggunakan cipher lama (Blowfish) alih-alih AES, kuncinya bukan biner dll. Komunitas SO harus benar-benar menghentikan upvoting enkripsi / dekripsi yang hanya "berfungsi" dan mulai upvoting jawaban yang dikenal aman. Jika Anda tidak tahu pasti, jangan memilih.
Maarten Bodewes
3
Saya agak melakukan ini dengan mcrypt_encryptmengganti kode sampel : php.net/manual/en/function.mcrypt-encrypt.php . Perhatikan bahwa meninjaunya sekarang mungkin harus memiliki rtrimkarakter "\0"for pada akhirnya.
Maarten Bodewes
4
Jawaban yang benar adalah dengan menggunakan sesuatu seperti defuse / php-enkripsi daripada menulis kode mcrypt Anda sendiri.
Scott Arciszewski
18

Untuk kerangka 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 terenkripsi tidak akan aman.

Somnath Muluk
sumber
1
Tentu, ini mungkin mudah digunakan. Tetapi apakah itu aman? Bagaimana cara mengatasi masalah di stackoverflow.com/a/30159120/781723 ? Apakah ia menggunakan enkripsi yang diautentikasi? Apakah itu menghindari kerentanan saluran samping dan memastikan pemeriksaan kesetaraan waktu-konstan? Apakah ia menggunakan kunci yang benar-benar acak daripada kata sandi / frasa sandi? Apakah ini menggunakan mode operasi yang sesuai? Apakah itu menghasilkan IV acak dengan benar?
DW
10

Diperbarui

Versi siap PHP 7. Ini menggunakan fungsi openssl_encrypt dari Perpustakaan PHP OpenSSL .

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', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);
夏 期 劇場
sumber
1
Ini adalah versi yang lebih baik dan jauh lebih aman. Terima kasih, ini berfungsi seperti yang diharapkan juga.
1
bagaimana Anda membuat dan di mana Anda menyimpan kunci enkripsi?
user2800464
7

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, metode enkripsi DES 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.

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


Idealnya Anda memiliki - atau bisa mendapatkan - akses ke pustaka mcrypt PHP, karena berbagai tugas yang sangat populer dan sangat berguna. Berikut ini adalah beberapa jenis enkripsi dan beberapa kode contoh: 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 kripto 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 yang terjadi. Hukuman finansial bisa sangat besar, jadi lebih baik menggunakan layanan dan mengirimkan tanggung jawab kepada mereka.

3) Segala jenis enkripsi yang mudah diterapkan, 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.

Bagaimanapun, bersenang-senang :)

BrianH
sumber
9
Eww, DES. Dimana aes?
Patashu
2
Terima kasih! Tetapi beberapa masalah. Saya mendapatkan M�������f=�_=karakter aneh sebagai yang terenkripsi. Tidak bisakah saya mendapatkan karakter sederhana? Seperti: 2a2ffa8f13220befbe30819047e23b2c. Juga, tidak bisakah saya mengubah PANJANG $key_value(tetap ke 8 ???) dan PANJANG output $encrypted_text? (tidak bisakah panjangnya 32 atau 64 atau lebih lama ??)
夏 期 劇場
3
@ 夏 期 劇場 Hasil enkripsi adalah data biner. Jika Anda membutuhkannya agar dapat dibaca manusia, gunakan basis64 atau hex encoding di atasnya. 'Tidak bisakah saya mengubah panjang nilai kunci?' Algoritma enkripsi simetris yang berbeda memiliki persyaratan yang berbeda untuk nilai kunci. 'dan PANJANG hasil ...' Panjang teks terenkripsi harus setidaknya selama teks asli, atau tidak ada informasi yang cukup untuk membuat ulang teks asli. (Ini adalah penerapan prinsip Pigeonhole.) BTW, Anda harus menggunakan AES, bukan DES. DES mudah pecah dan tidak aman lagi.
Patashu
8
mcrypt_ecb telah DIHAPUSKAN pada PHP 5.5.0 Mengandalkan fungsi ini sangat tidak dianjurkan. php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari
1
@BrianDHall Alasan ini masih turun-suara adalah karena mode ECB tidak aman (gunakan CBC, CTR, GCM, atau Poly1305), DES lemah (Anda ingin AES, yang MCRYPT_RIJNDAEL_128), dan ciphertext harus diotentikasi ( hash_hmac(), diverifikasi dengan hash_equals()).
Scott Arciszewski
7

Jika Anda tidak ingin menggunakan perpustakaan (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);
Ascon
sumber
Apakah ini bisa menjadi pengganti stackoverflow.com/a/16606352/126833 ? Saya telah menggunakan yang pertama sampai host saya ditingkatkan ke PHP 7.2.
anjanesh
@anjanesh Anda tidak akan dapat mendekripsi data lama dengan yang satu ini (algoritma berbeda + yang satu ini juga memeriksa tanda tangan)
Ascon
2
Dalam kasus Anda mungkin ini harus dilakukan:define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon
Ini Super!
anjanesh
2

Ini adalah metode ringkas untuk mengenkripsi / mendekripsi string dengan PHP menggunakan AES256 CBC :

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

Pemakaian:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");
Marco Concas
sumber
0

Kode di bawah ini berfungsi di php untuk semua string dengan karakter khusus

   // 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);
Javed
sumber