Як ви шифруєте та розшифровуєте рядок PHP?


225

Що я маю на увазі:

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

Можливо, щось на кшталт:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • Як можна зробити це в PHP?

Спроба використовувати Crypt_Blowfish, але це не спрацювало.


35
@Rogue Він не хоче хеш, він хоче симетричне шифрування (як AES), він просто не знає, як це називається. (А тепер він так і робить :))
Паташу

наскільки безпечно це потрібно?

3
@ 夏 期 劇場, Ви не «соліте» симетричне шифрування, ви використовуєте ключ. Ключ повинен зберігатися в таємниці. Сіль може бути загальнодоступною, не завдаючи шкоди безпеці (доки сіль для всіх відрізняється), і це термін, який використовується в хешировании паролів.
Паташу

2
Вам потрібна Сіль (приватний ключ), відкритий ключ, алгоритм шифрування типу AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy

8
@CristianFlorea Автор цього допису в блозі використовує терміни, які просто не мають жодного сенсу в контексті симетричного шифрування. У AES немає публічного ключа, а також солі. Є один ключ; це потрібно зберігати в таємниці. У деяких режимах роботи є IV, який не повинен бути секретним, але IV не є сіллю (залежно від режиму, він може мати зовсім інші вимоги) і не повинен бути секретним, тоді як власне ключ шифрування абсолютно не може бути відкритим. Публічний / приватний ключ застосовується до асиметричної криптовалюти, але не має нічого спільного з AES.
cpast

Відповіді:


410

Перш ніж робити щось далі, намагайтеся зрозуміти різницю між шифруванням та автентифікацією , і чому ви, ймовірно, хочете автентифіковане шифрування, а не просто шифрування .

Для реалізації автентифікованого шифрування потрібно зашифрувати, а потім MAC. Порядок шифрування та автентифікації дуже важливий! Одна з існуючих відповідей на це питання допустила цю помилку; як і багато бібліотек криптовалют, написаних на PHP.

Вам слід уникати впровадження власної криптографії , а натомість використовувати захищену бібліотеку, написану та переглянуту експертами з криптографії.

Оновлення: PHP 7.2 тепер забезпечує лібсодіум ! Для кращої безпеки оновіть ваші системи для використання PHP 7.2 або новішої версії та лише дотримуйтесь порад лібсодіуму в цій відповіді.

Використовуйте libsodium, якщо у вас є доступ до PECL (або natry_compat, якщо ви хочете libsodium без PECL); в іншому випадку ...
Використовуйте defuse / php-шифрування ; не котиться власна криптовалюта!

Обидві бібліотеки, зв'язані вище, дозволяють легко та безболісно реалізувати автентифіковане шифрування у власних бібліотеках.

Якщо ви все ще хочете написати та розгорнути власну бібліотеку криптовалют, проти звичайної мудрості кожного експерта з криптографії в Інтернеті, це кроки, які вам доведеться зробити.

Шифрування:

  1. Шифруйте за допомогою AES в режимі CTR. Ви також можете використовувати GCM (що усуває потребу в окремому MAC). Крім того, ChaCha20 і Salsa20 (надані лібсодіумом ) є потоковими шифрами і не потребують спеціальних режимах.
  2. Якщо ви не вибрали GCM вище, вам слід автентифікувати шифротекст за допомогою HMAC-SHA-256 (або, для шифрів потоку, Poly1305 - більшість ліцензійних API це робить для вас). MAC повинен охоплювати як IV, так і шифротекст!

Розшифровка:

  1. Якщо не використовуються Poly1305 або GCM, перерахуйте MAC шифротексту та порівняйте його з MAC, який був надісланий за допомогою hash_equals(). Якщо це не вдається, перервіть.
  2. Розшифруйте повідомлення.

Інші міркування щодо дизайну:

  1. Ніколи нічого не стискайте. Шифротекст не стискається; стиснення прямого тексту перед шифруванням може призвести до витоку інформації (наприклад, ЗЛОЧИНЕННЯ та НАРУШЕННЯ на TLS).
  2. Переконайтеся, що ви використовуєте mb_strlen()та mb_substr(), використовуючи '8bit'режим набору символів, для запобігання mbstring.func_overloadпроблемам.
  3. IV повинні генеруватися за допомогою CSPRNG ; Якщо ви використовуєте mcrypt_create_iv(), НЕ ВИКОРИСТОВУЙТЕMCRYPT_RAND !
  4. Якщо ви не використовуєте конструкцію AEAD, ЗАВЖДИ шифруйте потім MAC!
  5. bin2hex(), base64_encode()і т.д. може просочити інформацію про ваші ключі шифрування через таймінги кешу. Уникайте їх, якщо можливо.

Навіть якщо ви будете дотримуватися наведених тут порад, багато чого може піти не так з криптографією. Завжди попросіть експерта з криптографії переглянути вашу реалізацію. Якщо вам не пощастило бути особистими друзями зі студентом криптографії у вашому місцевому університеті, ви завжди можете спробувати форум обміну криптовалютою для отримання консультації.

Якщо вам потрібен професійний аналіз вашої реалізації, ви завжди можете найняти авторитетну команду консультантів з питань безпеки, щоб переглянути ваш код криптографії PHP (розкриття: мій роботодавець).

Важливо: Коли не використовувати шифрування

Не шифруйте паролі . Натомістьви хочете їх хеш , використовуючи один із цих алгоритмів хешування:

Ніколи не використовуйте хеш-функції загального призначення (MD5, SHA256) для зберігання паролів.

Не шифруйте параметри URL-адрес . Це неправильний інструмент для роботи.

Приклад шифрування рядків PHP з Libsodium

Якщо ви перебуваєте на PHP <7,2 або іншим способом не встановлено лібонатрій, ви можете використовувати натрію_компат для досягнення того ж результату (хоча і повільніше).

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

Потім перевірити це:

<?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 - лібсодіум виготовляється легше

Один з проектів, над якими я працював, - це бібліотека шифрування під назвою Halite , яка має на меті зробити лібсодіум простішим та інтуїтивнішим.

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

Усі основні криптографії обробляються лібсодієм.

Приклад з дефузією / 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);

Примітка : Crypto::encrypt()повертає шістнадцятковий вихід.

Керування ключами шифрування

Якщо ви спокусилися скористатися "паролем", зупиніться прямо зараз. Вам потрібен випадковий 128-розрядний ключ шифрування, а не пам'ятний для людини пароль.

Ви можете зберігати ключ шифрування для довготривалого використання так:

$storeMe = bin2hex($key);

І, за запитом, ви можете отримати його так:

$key = hex2bin($storeMe);

Я настійно рекомендую просто зберігати випадково створений ключ для тривалого використання замість будь-якого пароля в якості ключа (або для отримання ключа).

Якщо ви використовуєте бібліотеку Defuse:

"Але я дуже хочу використовувати пароль."

Це погана ідея, але добре, ось як це зробити безпечно.

По-перше, генеруйте випадковий ключ і зберігайте його в константі.

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

Зауважте, що ви додаєте додаткову роботу і можете просто використовувати цю константу як ключ і заощадити собі багато душі!

Потім використовуйте PBKDF2 (як-от так), щоб отримати відповідний ключ шифрування з вашого пароля, а не шифрувати безпосередньо паролем.

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

Не використовуйте лише 16-символьний пароль. Ваш ключ шифрування буде комічно зламаний.


3
Не шифруйте паролі , хешуйте їх password_hash()і не перевіряйте password_verify().
Скотт Арчішевський

2
"Не стискайте нічого ніколи". Ви маєте на увазі, як це роблять HTTP, spdy та інші протоколи? До TLS? Абсолютистські поради багато?
Tiberiu-Ionuț Stan

1
@ScottArciszewski Мені подобається ваш коментар щодо ключа "// Зробіть це один раз, а потім збережіть його якось:" .. якось, лол :)) ну як щодо зберігання цього "ключа" (який є об'єктом) як простого рядка, жорсткого коду? Мені потрібен сам ключ, як рядок. Чи можу я його якось отримати від цього об’єкта? Спасибі
Андрій

2
Thx, мені довелося просто змінити один рядок, щоб зробити ваші приклади натрію справними:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Олексій Озеров

1
Оце Так! +1 за згадування про нешифрування параметрів URL-адреси. Мені дуже сподобалась надана вами стаття: paragonie.com/blog/2015/09/…
Ліннель Еммануель Нері

73

Я спізнююсь на вечірку, але шукаючи правильний спосіб зробити це, я натрапив на цю сторінку, це була одна з найпопулярніших вертань пошуку Google, тому мені сподобається поділитися своїм поглядом на проблему, яку я вважаю такою актуальний на момент написання цього повідомлення (початок 2017 року). З PHP 7.1.0 mcrypt_decryptі mcrypt_encryptбуде збиратися застарілим, тому для створення майбутнього доказного коду слід використовувати openssl_encrypt і openssl_decrypt

Ви можете зробити щось на кшталт:

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

Важливо : тут використовується режим ECB , який не захищено. Якщо ви хочете просте рішення, не проходячи крах курсу криптографії, не пишіть його самостійно, просто використовуйте бібліотеку.

Ви також можете використовувати будь-які інші методи відсікання, залежно від потреб у безпеці. Щоб дізнатися про доступні методи чіппер, будь ласка, перегляньте функцію openssl_get_cipher_methods .


10
Дякую, я здивований, що ця проста і зрозуміла відповідь не викликає більшої популярності. Я б краще не читав дискусію на 10 сторінок на тему, як головна відповідь, коли все, що мені потрібно, - шифрувати / розшифровувати простий рядок.
Лоран

4
Це не безпечна відповідь. Режим ECB не повинен використовуватися. Якщо ви хочете "просту і зрозумілу відповідь", просто використовуйте бібліотеку .
Скотт Арчішевський

2
@ScottArciszewski, так, я визнаю, я говорив занадто швидко, шукаючи простий код. Я з тих пір додав IV і використовую CBC у власному коді, що досить добре для мого використання.
Лоран

Прочитайте це і перегляньте . У режимі CBC зловмисник може повністю змінити повідомлення. Якщо повідомлення є файлом, зловмисник може перевернути біти і поп calc.exe. Ризики несанкціонованого шифрування є серйозними.
Скотт Арчішевський

7
Все залежить від випадку використання! Бувають випадки, коли це ідеально ТОПЛИВО. Наприклад, я хочу передати параметр GET зі сторінки на сторінку, скажімо, prod_id=123але я просто не хочу зробити 123 читабельним для всіх, однак навіть якщо вони зможуть його прочитати, це не буде проблемою. Зловмисник, який зможе замінити 123 на користувальницьке значення, не спричинить ніякої шкоди, він / вона зможе отримати детальну інформацію про будь-який інший продукт, але середній користувач Joe не матиме поняття, як отримати детальну інформацію про продукт 124, наприклад. Для такого сценарію це ідеальне рішення, для безпеки - це не піде!
Еміль Борконі

43

Чого не робити

ПОПЕРЕДЖЕННЯ.
У цій відповіді використовується ЕЦБ . ECB - це не режим шифрування, це лише будівельний блок. Використання ECB, як показано у цій відповіді, насправді не шифрує рядок надійно. Не використовуйте ECB у своєму коді. Дивіться відповідь Скотта для хорошого рішення.

Я отримав це на собі. Насправді я знайшов якусь відповідь на Google і просто щось змінив. Результат, однак, є абсолютно незахищеним.

<?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
Ви можете користувачем "MCRYPT_MODE_CBC" замість "MCRYPT_MODE_ECB", щоб забезпечити більшу безпеку.
Parixit

10
Рамеш, це тому, що ти отримуєш необроблені зашифровані дані. Ви можете отримати приємнішу версію зашифрованих даних, використовуючи base64, наприклад, так base64_encode(encrypt($string)):decrypt(base64_decode($encrypted))
Розшифрувати

82
Попередження: це небезпечно . Режим ECB не слід використовувати для рядків, ECB не приймає IV, це не автентифіковано, він використовує старий шифр (Blowfish) замість AES, ключ не двійковий тощо . Спільнота SO дійсно повинна припинити запроваджувати шифрування / дешифрування, що просто "працює", і почати оскаржувати відповіді, які, як відомо, є безпечними. Якщо ви цього точно не знаєте, не голосуйте.
Maarten Bodewes

3
Я це зробив уже за допомогою mcrypt_encryptзаміненого зразкового коду : php.net/manual/en/function.mcrypt-encrypt.php . Зауважте, що переглядаючи його зараз, мабуть, він повинен мати знак rtrimдля "\0"кінця.
Maarten Bodewes

4
Правильна відповідь - використовувати щось на кшталт defuse / php-шифрування замість написання власного коду mcrypt.
Скотт Арчішевський

18

Для рамок Laravel

Якщо ви використовуєте Laravel Framework, тоді простіше шифрувати та дешифрувати за допомогою внутрішніх функцій.

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

Примітка. Обов'язково встановіть випадковий рядок 16, 24 або 32 символів у ключовому варіанті файла config / app.php. Інакше зашифровані значення не будуть захищені.


1
Звичайно, це може бути просто у використанні. Але це безпечно? Як він вирішує проблеми в stackoverflow.com/a/30159120/781723 ? Чи використовується автентифіковане шифрування? Чи уникає вразливості бічних каналів та забезпечує перевірку рівності постійного часу? Чи використовує він справді випадковий ключ, а не пароль / пароль? Чи використовується в ньому відповідний режим роботи? Чи правильно він генерує випадкові IV?
DW

10

Оновлено

Готова версія PHP 7 Він використовує функцію openssl_encrypt з бібліотеки 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);

1
Це краща та набагато безпечніша версія. Спасибі, він працює, як і очікувалося.

1
як ви створюєте і де зберігаєте ключ шифрування?
користувач2800464

7

Історична примітка: Це було написано під час PHP4. Це те, що ми зараз називаємо "застарілим кодом".

Цю відповідь я залишив для історичних цілей - але деякі методи зараз застаріли, метод шифрування DES не є рекомендованою практикою тощо.

Я не оновлював цей код з двох причин: 1) Я більше не працюю з методами шифрування вручну в PHP, і 2) цей код все ще служить тій меті, якою він був призначений: продемонструвати мінімальну, спрощену концепцію того, як може працювати шифрування. в PHP

Якщо ви знайдете подібне спрощене джерело "шифрування PHP для манекенів", яке може запустити людей у ​​10-20 рядків коду чи менше, дайте мені знати в коментарях.

Крім цього, будь ласка, насолоджуйтесь цим класичним епізодом мінімалістичного відповіді на шифрування PHP4 ранньої епохи.


В ідеалі ви маєте - або можете отримати - доступ до бібліотеки mcrypt PHP, як його, безумовно, популярних і дуже корисних різноманітних завдань. Ось збірка різних видів шифрування та деякий приклад коду: Методи шифрування в 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 ); 
?> 

Кілька попереджень:

1) Ніколи не використовуйте зворотне або "симетричне" шифрування, коли односторонній хеш буде робити.

2) Якщо дані справді чутливі, як-от кредитна картка чи номери соціального страхування, зупиніться; вам потрібно більше, ніж будь-який простий фрагмент коду забезпечить, але, швидше, вам потрібна бібліотека криптовалют, призначена для цієї мети, і значна кількість часу для дослідження необхідних методів. Крім того, програмна криптовалюта, ймовірно, <10% безпеки конфіденційних даних. Це як би переобладнати атомну електростанцію - прийміть, що завдання є небезпечним і складним та поза вашими знаннями, якщо це так. Фінансові стягнення можуть бути величезними, тому краще скористатися послугою та відповідальністю за них.

3) Будь-яке легко реалізоване шифрування, перелічене тут, може розумно захистити незначно важливу інформацію, яку ви хочете уберегти від сторонніх очей або обмежити вплив у разі випадкового / навмисного витоку. Але бачимо, як ключ зберігається у простому тексті на веб-сервері, якщо вони можуть отримати дані, вони можуть отримати ключ розшифровки.

Як би там не було, весело :)


9
Eww, DES. Де AES?
Паташу

2
Дякую! Але деякі питання. Я отримую M�������f=�_=дивні символи як зашифровані. Не можу я отримати простих символів? Як: 2a2ffa8f13220befbe30819047e23b2c. Крім того, я не можу змінити LENGTH $key_value(фіксований на 8 ???) та LENGTH вихід $encrypted_text? (чи не може це бути 32 чи 64 довгими чи довше ??)
夏 期 劇場

3
@ 夏 期 劇場 Результатом шифрування є двійкові дані. Якщо вам потрібно, щоб воно було читабельним для людей, використовуйте кодування base64 або hex. "Чи не можу я змінити довжину ключового значення?" Різні алгоритми симетричного шифрування мають різні вимоги до ключового значення. 'і ДІЛЬНІСТЬ виводу ...' Довжина зашифрованого тексту повинна бути не менше, ніж оригінальний текст, інакше не вистачає інформації для відтворення оригінального тексту. (Це застосування принципу Pigeonhole.) BTW, вам слід використовувати AES замість DES. DES легко зламаний і більше не захищений.
Паташу

8
mcrypt_ecb було знято з PHP 5.5.0. Покладатися на цю функцію дуже не рекомендується. php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari

1
@BrianDHall Причина цього все-таки знижується - це те, що режим ECB не є безпечним (використовуйте CBC, CTR, GCM або Poly1305), DES слабкий (ви хочете AES, який є MCRYPT_RIJNDAEL_128), а шифротексти повинні бути автентифіковані ( hash_hmac()перевірено) з hash_equals()).
Скотт Арчішевський

7

Якщо ви не хочете використовувати бібліотеку (яку вам слід), тоді використовуйте щось подібне (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);

Чи може це замінити stackoverflow.com/a/16606352/126833 ? Я використовую перший, поки мій хост не оновився до PHP 7.2.
anjanesh

@anjanesh ви не зможете розшифрувати старі дані за допомогою цього (різні алгоритми + цей також перевіряє підпис)
Ascon

2
У вашому випадку, мабуть, так і слід: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);
Аскон

Це супер!
anjanesh

2

Це компактні методи шифрування / дешифрування рядків за допомогою PHP за допомогою 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));
}

Використання:

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

0

Нижче код працює у php для всіх рядків із спеціальним символом

   // 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.