Làm thế nào để bạn mã hóa và giải mã một chuỗi PHP?


225

Ý của tôi là:

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

Có lẽ một cái gì đó như:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • Trong PHP, làm thế nào bạn có thể làm điều này?

Đã cố sử dụng Crypt_Blowfishnhưng nó không hiệu quả với tôi.


35
@Rogue Anh ấy không muốn băm, anh ấy muốn mã hóa đối xứng (như AES), anh ấy chỉ không biết nó được gọi là gì. (Và bây giờ anh ấy làm :))
Patashu

nó cần an toàn đến mức nào?

3
@ 夏 期, Bạn không mã hóa đối xứng 'muối', bạn sử dụng khóa. Một chìa khóa phải được giữ bí mật. Một muối có thể được công khai mà không gây tổn hại đến an ninh (miễn là muối của mọi người là khác nhau) và đó là một thuật ngữ được sử dụng trong việc băm mật khẩu.
Patashu

2
Bạn cần một Salt (private key), một khóa công khai một thuật toán mã hóa như AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy

8
@CristianFlorea Tác giả của bài đăng trên blog đó sử dụng các thuật ngữ đơn giản là không có ý nghĩa nhỏ nhất trong bối cảnh mã hóa đối xứng. Không có khóa công khai với AES, cũng không có muối. Có một chìa khóa duy nhất; nó phải được giữ bí mật Trong một số chế độ hoạt động có IV không cần phải bí mật, nhưng IV không phải là muối (tùy thuộc vào chế độ, nó có thể có các yêu cầu khá khác nhau) và không cần phải bí mật, trong khi khóa mã hóa thực tế hoàn toàn không thể công khai. Khóa công khai / riêng áp dụng cho tiền điện tử bất đối xứng, nhưng không liên quan gì đến AES.
cpast

Câu trả lời:


410

Trước khi bạn làm bất cứ điều gì hơn nữa, hãy tìm cách hiểu sự khác biệt giữa mã hóaxác thực và lý do tại sao bạn có thể muốn mã hóa được xác thực thay vì chỉ mã hóa .

Để thực hiện mã hóa xác thực, bạn muốn Mã hóa sau đó MAC. Thứ tự mã hóa và xác thực là rất quan trọng! Một trong những câu trả lời hiện có cho câu hỏi này đã mắc lỗi này; cũng như nhiều thư viện mật mã được viết bằng PHP.

Bạn nên tránh thực hiện mật mã của riêng mình , và thay vào đó hãy sử dụng một thư viện an toàn được viết và xem xét bởi các chuyên gia về mật mã.

Cập nhật: PHP 7.2 hiện cung cấp libsodium ! Để bảo mật tốt nhất, hãy cập nhật các hệ thống của bạn để sử dụng PHP 7.2 trở lên và chỉ làm theo lời khuyên libsodium trong câu trả lời này.

Sử dụng libsodium nếu bạn có quyền truy cập PECL (hoặc sodium_compat nếu bạn muốn libsodium không có PECL); mặt khác ...
Sử dụng mã hóa defuse / php ; đừng cuộn mật mã của riêng bạn!

Cả hai thư viện được liên kết ở trên giúp việc triển khai mã hóa được xác thực vào thư viện của bạn trở nên dễ dàng và không đau đớn.

Nếu bạn vẫn muốn viết và triển khai thư viện mật mã của riêng mình, chống lại sự khôn ngoan thông thường của mọi chuyên gia mật mã trên Internet, đây là những bước bạn sẽ phải thực hiện.

Mã hóa:

  1. Mã hóa bằng AES trong chế độ CTR. Bạn cũng có thể sử dụng GCM (loại bỏ nhu cầu về MAC riêng). Ngoài ra, ChaCha20 và Salsa20 (được cung cấp bởi libsodium ) là mật mã luồng và không cần chế độ đặc biệt.
  2. Trừ khi bạn chọn GCM ở trên, bạn nên xác thực bản mã bằng HMAC-SHA-256 (hoặc, đối với mật mã luồng, Poly1305 - hầu hết các API libsodium làm điều này cho bạn). MAC nên bao gồm IV cũng như bản mã!

Giải mã:

  1. Trừ khi Poly1305 hoặc GCM được sử dụng, hãy tính lại MAC của bản mã và so sánh nó với MAC được gửi bằng cách sử dụng hash_equals(). Nếu thất bại, hãy hủy bỏ.
  2. Giải mã tin nhắn.

Các cân nhắc thiết kế khác:

  1. Đừng nén bất cứ điều gì bao giờ. Bản mã không thể nén được; nén bản rõ trước khi mã hóa có thể dẫn đến rò rỉ thông tin (ví dụ CRIME và BREACH trên TLS).
  2. Đảm bảo bạn sử dụng mb_strlen()mb_substr(), sử dụng '8bit'chế độ đặt ký tự để ngăn sự mbstring.func_overloadcố.
  3. IV nên được tạo bằng CSPRNG ; Nếu bạn đang sử dụng mcrypt_create_iv(), KHÔNG SỬ DỤNGMCRYPT_RAND !
  4. Trừ khi bạn đang sử dụng cấu trúc AEAD, LUÔN LUÔN mã hóa rồi MAC!
  5. bin2hex(),, base64_encode()vv có thể rò rỉ thông tin về các khóa mã hóa của bạn thông qua thời gian bộ đệm. Tránh chúng nếu có thể.

Ngay cả khi bạn làm theo lời khuyên được đưa ra ở đây, rất nhiều điều có thể sai với mật mã. Luôn luôn có một chuyên gia mật mã xem xét thực hiện của bạn. Nếu bạn không đủ may mắn để trở thành bạn bè cá nhân với một sinh viên mật mã tại trường đại học địa phương, bạn luôn có thể thử diễn đàn Trao đổi mật mã để được tư vấn.

Nếu bạn cần một phân tích chuyên nghiệp về việc triển khai của mình, bạn luôn có thể thuê một nhóm các chuyên gia tư vấn bảo mật có uy tín để xem xét mã mật mã PHP của bạn (tiết lộ: chủ nhân của tôi).

Quan trọng: Khi nào không sử dụng mã hóa

Không mã hóa mật khẩu . Thay vào đó,bạn muốn băm chúng, sử dụng một trong các thuật toán băm mật khẩu này:

Không bao giờ sử dụng hàm băm có mục đích chung (MD5, SHA256) để lưu trữ mật khẩu.

Không mã hóa tham số URL . Đó là công cụ sai cho công việc.

Ví dụ mã hóa chuỗi PHP với Libsodium

Nếu bạn đang sử dụng PHP <7.2 hoặc không cài đặt libsodium, bạn có thể sử dụng sodium_compat để thực hiện cùng một kết quả (mặc dù chậm hơn).

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

Sau đó, để kiểm tra nó:

<?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 được thực hiện dễ dàng hơn

Một trong những dự án tôi đang thực hiện là một thư viện mã hóa có tên Halite , nhằm mục đích làm cho libsodium dễ dàng và trực quan hơn.

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

Tất cả các mật mã cơ bản được xử lý bởi libsodium.

Ví dụ với mã hóa defuse / php

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

Lưu ý : Crypto::encrypt()trả về đầu ra được mã hóa hex.

Quản lý khóa mã hóa

Nếu bạn muốn sử dụng "mật khẩu", hãy dừng ngay bây giờ. Bạn cần một khóa mã hóa 128 bit ngẫu nhiên, không phải mật khẩu dễ nhớ của con người.

Bạn có thể lưu trữ khóa mã hóa để sử dụng lâu dài như vậy:

$storeMe = bin2hex($key);

Và, theo yêu cầu, bạn có thể truy xuất nó như vậy:

$key = hex2bin($storeMe);

Tôi mạnh mẽ khuyên bạn nên chỉ lưu trữ một chìa khóa được tạo ra một cách ngẫu nhiên để sử dụng lâu dài thay vì bất kỳ loại mật khẩu là chìa khóa (hoặc để lấy được chìa khóa).

Nếu bạn đang sử dụng thư viện của Defuse:

"Nhưng tôi thực sự muốn sử dụng mật khẩu."

Đó là một ý tưởng tồi, nhưng không sao, đây là cách thực hiện nó một cách an toàn.

Đầu tiên, tạo một khóa ngẫu nhiên và lưu trữ nó trong một hằng số.

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

Lưu ý rằng bạn đang thêm công việc làm thêm và chỉ có thể sử dụng hằng số này làm chìa khóa và tiết kiệm cho mình rất nhiều nỗi đau!

Sau đó, sử dụng PBKDF2 (như vậy) để lấy khóa mã hóa phù hợp từ mật khẩu của bạn thay vì mã hóa trực tiếp bằng mật khẩu của bạn.

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

Đừng chỉ sử dụng mật khẩu 16 ký tự. Khóa mã hóa của bạn sẽ bị hỏng.


3
Không mã hóa mật khẩu , băm chúng password_hash()và kiểm tra chúng với password_verify().
Scott Arciszewski

2
"Đừng nén bất cứ thứ gì bao giờ." Bạn có nghĩa là như HTTP, spdy và các giao thức khác làm gì? Trước TLS? Tư vấn tuyệt đối nhiều?
Tiberiu-Ionuț Stan

1
@ScottArciszewski Tôi thích nhận xét của bạn về khóa "// Làm điều này một lần rồi lưu nó bằng cách nào đó:" .. bằng cách nào đó, lol :)) làm thế nào về việc lưu trữ 'khóa' này (là đối tượng) dưới dạng chuỗi đơn giản, được mã hóa cứng? Tôi cần chìa khóa chính nó, như một chuỗi. Tôi có thể lấy nó từ đối tượng này bằng cách nào đó? Cảm ơn
Andrew

2
Thx, tôi chỉ phải sửa đổi một dòng để làm cho các ví dụ natri của bạn hoạt động:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey Ozerov

1
Ồ +1 để đề cập không mã hóa các tham số URL. Tôi thực sự thích bài viết mà bạn cung cấp: paragonie.com/blog/2015/09/
Kẻ

73

Tôi đến bữa tiệc muộn, nhưng tìm kiếm cách thức chính xác để làm điều đó Tôi tình cờ thấy trang này là một trong những lợi nhuận tìm kiếm hàng đầu của Google, vì vậy tôi muốn chia sẻ quan điểm của mình về vấn đề mà tôi cho là như vậy cập nhật tại thời điểm viết bài này (đầu năm 2017). Từ PHP 7.1.0, mcrypt_decryptmcrypt_encryptsẽ không được dùng nữa, vì vậy, việc xây dựng mã bằng chứng trong tương lai nên sử dụng openssl_encryptopenssl_decrypt

Bạn có thể làm một cái gì đó như:

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

Quan trọng : Điều này sử dụng chế độ ECB , không an toàn. Nếu bạn muốn một giải pháp đơn giản mà không cần tham gia khóa học về kỹ thuật mã hóa, đừng tự viết nó, chỉ cần sử dụng một thư viện.

Bạn có thể sử dụng bất kỳ phương pháp chipper nào khác, tùy thuộc vào nhu cầu bảo mật của bạn. Để tìm hiểu các phương pháp chipper có sẵn, vui lòng xem hàm openssl_get_codes_methods .


10
Cảm ơn bạn, tôi ngạc nhiên câu trả lời đơn giản và rõ ràng này không được đánh giá cao hơn. Tôi không muốn đọc một cuộc thảo luận 10 trang về chủ đề như câu trả lời hàng đầu khi tất cả những gì tôi muốn là mã hóa / giải mã một chuỗi đơn giản.
nguyệt quế

4
Đây không phải là một câu trả lời an toàn. Chế độ ECB không nên được sử dụng. Nếu bạn muốn có một "câu trả lời đơn giản và rõ ràng", chỉ cần sử dụng một thư viện .
Scott Arciszewski

2
@ScottArciszewski, vâng, tôi thừa nhận tôi đã nói quá nhanh trong khi tìm kiếm một số mã đơn giản. Kể từ đó tôi đã thêm IV và sử dụng CBC trong mã riêng của mình, đủ tốt để sử dụng.
nguyệt quế

Đọc này và xem xét lại . Với chế độ CBC, kẻ tấn công hoàn toàn có thể thay đổi tin nhắn. Nếu tin nhắn là một tập tin, kẻ tấn công có thể lật các bit và pop calc.exe. Những rủi ro của mã hóa không được xác thực là nghiêm trọng.
Scott Arciszewski

7
Tất cả phụ thuộc vào trường hợp sử dụng! Có những trường hợp khi điều này là hoàn hảo. Ví dụ: tôi muốn truyền tham số GET từ trang này sang trang khác, giả sử prod_id=123tôi không muốn làm cho 123 có thể đọc được cho mọi người, tuy nhiên ngay cả khi họ có thể đọc nó, nó sẽ không thành vấn đề. Kẻ tấn công có thể thay thế 123 thành giá trị tùy chỉnh sẽ không gây ra bất kỳ tổn hại nào, anh ta / cô ta sẽ chỉ có thể nhận thông tin chi tiết về bất kỳ sản phẩm nào khác, nhưng Người dùng trung bình Joe sẽ không biết cách lấy thông tin chi tiết cho sản phẩm 124 chẳng hạn. Đối với một kịch bản như thế này, đó là một giải pháp hoàn hảo, vì an ninh là không nên!
Emil Borconi

43

Những gì không làm

CẢNH BÁO:
Câu trả lời này sử dụng ECB . ECB không phải là chế độ mã hóa, nó chỉ là một khối xây dựng. Sử dụng ECB như thể hiện trong câu trả lời này không thực sự mã hóa chuỗi một cách an toàn. Không sử dụng ECB trong mã của bạn. Xem câu trả lời của Scott cho một giải pháp tốt.

Tôi đã nhận nó trên bản thân mình. Trên thực tế tôi tìm thấy một số câu trả lời trên google và chỉ cần sửa đổi một cái gì đó. Kết quả là hoàn toàn không an toàn tuy nhiên.

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

8
Bạn có thể sử dụng "MCRYPT_MODE_CBC" thay vì "MCRYPT_MODE_ECB" để đảm bảo an toàn hơn.
Parixit

10
Ramesh, điều này là do bạn đang nhận được dữ liệu được mã hóa thô. Bạn có thể có được một phiên bản đẹp hơn của dữ liệu được mã hóa bằng cách sử dụng base64, như thế này: base64_encode(encrypt($string))- Để giải mã nó:decrypt(base64_decode($encrypted))
mendezcode

82
CẢNH BÁO: điều này không an toàn . Không nên sử dụng chế độ ECB cho chuỗi, ECB không lấy IV, điều này không được xác thực, nó sử dụng một mật mã cũ (Blowfish) thay vì AES, khóa không phải là nhị phân, v.v. Cộng đồng SO nên thực sự ngừng mã hóa / giải mã chỉ "hoạt động" và bắt đầu nâng cao các câu trả lời được biết là an toàn. Nếu bạn không biết điều đó chắc chắn, đừng bỏ phiếu.
Maarten Bodewes 3/2/2015

3
Tôi đã làm điều này bằng cách có mã mẫu mcrypt_encryptthay thế: php.net/manual/en/feft.mcrypt-encrypt.php . Lưu ý rằng xem lại nó bây giờ có lẽ nên có một rtrimký tự "\0"cho cuối.
Maarten Bodewes 4/2/2015

4
Câu trả lời đúng là sử dụng một cái gì đó như defuse / mã hóa php thay vì viết mã mcrypt của riêng bạn.
Scott Arciszewski

18

Đối với khung Laravel

Nếu bạn đang sử dụng khung công tác Laravel thì việc mã hóa và giải mã với các chức năng bên trong sẽ dễ dàng hơn.

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

Lưu ý: Đảm bảo đặt chuỗi ngẫu nhiên 16, 24 hoặc 32 ký tự trong tùy chọn chính của tệp config / app.php. Nếu không, các giá trị được mã hóa sẽ không được bảo mật.


1
Chắc chắn, nó có thể dễ sử dụng. Nhưng nó có an toàn không? Làm thế nào để nó giải quyết các vấn đề trong stackoverflow.com/a/30159120/781723 ? Nó có sử dụng mã hóa xác thực? Liệu nó có tránh được các lỗ hổng kênh bên và đảm bảo kiểm tra sự bình đẳng trong thời gian không đổi? Nó có sử dụng khóa thực sự ngẫu nhiên thay vì mật khẩu / cụm mật khẩu không? Liệu nó có sử dụng một chế độ hoạt động phù hợp? Liệu nó tạo ra IV ngẫu nhiên đúng cách?
DW

10

Đã cập nhật

Phiên bản PHP 7 đã sẵn sàng. Nó sử dụng hàm openssl_encrypt từ Thư viện OpenSSL PHP .

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

1
Đây là phiên bản tốt hơn và an toàn hơn nhiều. Cảm ơn, nó hoạt động như mong đợi quá.

1
Làm thế nào để bạn tạo và nơi bạn giữ khóa mã hóa?
dùng2800464

7

Ghi chú lịch sử: Điều này được viết vào thời điểm PHP4. Đây là những gì chúng ta gọi là "mã di sản" bây giờ.

Tôi đã để lại câu trả lời này cho các mục đích lịch sử - nhưng một số phương pháp hiện không được chấp nhận, phương pháp mã hóa DES không phải là một thực tiễn được đề xuất, v.v.

Tôi chưa cập nhật mã này vì hai lý do: 1) Tôi không còn làm việc với các phương thức mã hóa bằng tay trong PHP và 2) mã này vẫn phục vụ mục đích mà nó nhằm mục đích: thể hiện khái niệm đơn giản, tối thiểu về cách mã hóa có thể hoạt động trong PHP.

Nếu bạn tìm thấy một loại nguồn đơn giản tương tự, "mã hóa PHP cho người giả" có thể khiến mọi người bắt đầu trong 10-20 dòng mã hoặc ít hơn, hãy cho tôi biết trong các nhận xét.

Ngoài ra, vui lòng thưởng thức Tập cổ điển này về câu trả lời mã hóa tối thiểu PHP4 thời kỳ đầu.


Lý tưởng nhất là bạn có - hoặc có thể có được - quyền truy cập vào thư viện mcrypt PHP, vì một loạt các nhiệm vụ rất phổ biến và rất hữu ích của nó. Dưới đây là một loại mã hóa khác nhau và một số mã ví dụ: Kỹ thuật mã hóa trong 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 ); 
?> 

Một vài cảnh báo:

1) Không bao giờ sử dụng mã hóa đảo ngược hoặc "đối xứng" khi băm một chiều sẽ làm.

2) Nếu dữ liệu thực sự nhạy cảm, như thẻ tín dụng hoặc số an sinh xã hội, hãy dừng lại; bạn cần nhiều hơn bất kỳ đoạn mã đơn giản nào sẽ cung cấp, nhưng thay vào đó bạn cần một thư viện tiền điện tử được thiết kế cho mục đích này và một lượng thời gian đáng kể để nghiên cứu các phương pháp cần thiết. Hơn nữa, tiền điện tử phần mềm có thể <10% bảo mật dữ liệu nhạy cảm. Nó giống như việc xây dựng lại một nhà máy điện hạt nhân - chấp nhận rằng nhiệm vụ này nguy hiểm và khó khăn và vượt quá hiểu biết của bạn nếu đó là trường hợp. Các hình phạt tài chính có thể là rất lớn, vì vậy tốt hơn là sử dụng một dịch vụ và giao trách nhiệm cho họ.

3) Bất kỳ loại mã hóa nào có thể thực hiện dễ dàng, như được liệt kê ở đây, có thể bảo vệ một cách hợp lý thông tin quan trọng nhẹ mà bạn muốn tránh khỏi những con mắt tò mò hoặc hạn chế tiếp xúc trong trường hợp rò rỉ vô tình / cố ý. Nhưng xem làm thế nào khóa được lưu trữ trong văn bản đơn giản trên máy chủ web, nếu họ có thể lấy dữ liệu, họ có thể lấy khóa giải mã.

Hãy là như nó có thể, vui chơi :)


9
Ồ, MÔ TẢ. AES đâu rồi?
Patashu

2
Cảm ơn! Nhưng một số vấn đề. Tôi đang nhận được M�������f=�_=các ký tự lạ là mã hóa. Tôi không thể có được các nhân vật đơn giản? Giống như : 2a2ffa8f13220befbe30819047e23b2c. Ngoài ra, tôi không thể thay đổi LENGTH của $key_value(cố định thành 8 ???) và LENGTH của đầu ra $encrypted_text? (không thể dài 32 hay 64 hay lâu hơn nữa ??)
夏 期

3
@ 夏 期 Kết quả của mã hóa là dữ liệu nhị phân. Nếu bạn cần nó có thể đọc được bằng con người, hãy sử dụng mã hóa base64 hoặc hex trên nó. 'Tôi không thể thay đổi độ dài của giá trị khóa?' Các thuật toán mã hóa đối xứng khác nhau có các yêu cầu khác nhau cho giá trị khóa. 'và LENGTH của đầu ra ...' Độ dài của văn bản được mã hóa ít nhất phải dài bằng văn bản gốc hoặc nếu không thì không có đủ thông tin để tạo lại văn bản gốc. (Đây là một ứng dụng của nguyên tắc Pigeonhole.) BTW, bạn nên sử dụng AES thay vì DES. DES dễ bị phá vỡ và không an toàn nữa.
Patashu

8
mcrypt_ecb đã bị ĐỔI kể từ phiên bản PHP 5.5.0 Dựa vào chức năng này rất không được khuyến khích. php.net/manual/en/feft.mcrypt-ecb.php
Hafez Divandari

1
@BrianDHall Lý do điều này vẫn bị bỏ phiếu là vì chế độ ECB không an toàn (sử dụng CBC, CTR, GCM hoặc Poly1305), DES yếu (bạn muốn AES, đó là MCRYPT_RIJNDAEL_128) và mật mã phải được xác thực ( hash_hmac(), đã được xác minh với hash_equals()).
Scott Arciszewski

7

Nếu bạn không muốn sử dụng thư viện (mà bạn nên) thì hãy sử dụng cái gì đó như thế này (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);

Đây có thể là một sự thay thế cho stackoverflow.com/a/16606352/126833 không? Tôi đã sử dụng trước đây cho đến khi máy chủ của tôi nâng cấp lên PHP 7.2.
anjanesh

@anjanesh bạn sẽ không thể giải mã dữ liệu cũ bằng dữ liệu này (các thuật toán khác nhau + thuật toán này cũng kiểm tra chữ ký)
Ascon

2
Trong trường hợp của bạn có lẽ điều này nên làm: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

Đây là một siêu nhân !
anjanesh

2

Đây là những phương thức nhỏ gọn để mã hóa / giải mã chuỗi bằng PHP bằng cách sử dụng 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));
}

Sử dụng:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");

0

Mã bên dưới hoạt động trong php cho tất cả các chuỗi có ký tự đặc biệt

   // 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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.