Как зашифровать/расшифровать данные в php?


В настоящее время я студент и изучаю PHP, я пытаюсь сделать простое шифрование/дешифрование данных на PHP. Я провел некоторые онлайн-исследования, и некоторые из них были довольно запутанными (по крайней мере, для меня).

Вот что я пытаюсь сделать:

У меня есть таблица, состоящая из этих полей (Идентификатор пользователя, Имя пользователя, Имя пользователя, адрес электронной почты, пароль)

Я хочу, чтобы все поля были зашифрованы, а затем расшифрованы (можно ли использовать sha256 для шифрования/дешифрования, если их нет алгоритм шифрования)

Еще одна вещь, которую я хочу узнать, - это как создать один из способов hash(sha256) в сочетании с хорошей "солью". (В основном я просто хочу иметь простую реализацию шифрования/дешифрования, hash(sha256)+salt) Сэр/мэм, ваши ответы были бы очень полезны и были бы очень признательны. Спасибо++

Author: Scott Arciszewski, 2012-06-06

6 answers

Предисловие

Начиная с определения вашей таблицы:

- UserID
- Fname
- Lname
- Email
- Password
- IV

Вот изменения:

  1. Поля Fname, Lname и Email будет зашифрован с использованием симметричного шифра, предоставленного OpenSSL,
  2. Поле IV будет хранить вектор инициализации , используемый для шифрования. Требования к хранению зависят от используемого шифра и режима; подробнее об этом позже.
  3. Поле Password будет хэшировано с помощью односторонний хэш пароля,

Шифрование

Шифр и режим

Выбор наилучшего шифра и режима шифрования выходит за рамки этого ответа, но окончательный выбор влияет на размер как ключа шифрования, так и вектора инициализации; для этого сообщения мы будем использовать AES-256-CBC, который имеет фиксированный размер блока 16 байт и размер ключа 16, 24 или 32 байта.

Ключ шифрования

Хороший ключ шифрования - это двоичный двоичный объект, созданный с помощью надежного генератора случайных чисел. Рекомендуется использовать следующий пример (>= 5.3):

$key_size = 32; // 256 bits
$encryption_key = openssl_random_pseudo_bytes($key_size, $strong);
// $strong will be true if the key is crypto safe

Это можно сделать один или несколько раз (если вы хотите создать цепочку ключей шифрования). Держите их как можно более конфиденциальными.

IV

Вектор инициализации добавляет случайности в шифрование и требуется для режима CBC. В идеале эти значения должны использоваться только один раз (технически один раз на ключ шифрования), поэтому обновление любой части строки должно привести к ее регенерации.

Предусмотрена функция, которая поможет вам сгенерировать IV:

$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);

Пример

Давайте зашифруем поле имени, используя более ранние $encryption_key и $iv; для этого мы должны дополнить наши данные размером блока:

function pkcs7_pad($data, $size)
{
    $length = $size - strlen($data) % $size;
    return $data . str_repeat(chr($length), $length);
}

$name = 'Jack';
$enc_name = openssl_encrypt(
    pkcs7_pad($name, 16), // padded data
    'AES-256-CBC',        // cipher and mode
    $encryption_key,      // secret key
    0,                    // options (not used)
    $iv                   // initialisation vector
);

Требования к хранению

Зашифрованный вывод, как и IV, является двоичным; сохранение этих значений в базе данных может быть выполнено с помощью назначенных типов столбцов, таких как BINARY или VARBINARY.

Выходное значение, как и IV, является двоичным; для хранения этих значений в MySQL рассмотрите возможность использования BINARY или VARBINARY колонны. Если это не вариант, вы также можете преобразовать двоичные данные в текстовое представление с помощью base64_encode() или bin2hex(), для этого требуется от 33 % до 100% больше места для хранения.

Расшифровка

Расшифровка сохраненных значений аналогична:

function pkcs7_unpad($data)
{
    return substr($data, 0, -ord($data[strlen($data) - 1]));
}

$row = $result->fetch(PDO::FETCH_ASSOC); // read from database result
// $enc_name = base64_decode($row['Name']);
// $enc_name = hex2bin($row['Name']);
$enc_name = $row['Name'];
// $iv = base64_decode($row['IV']);
// $iv = hex2bin($row['IV']);
$iv = $row['IV'];

$name = pkcs7_unpad(openssl_decrypt(
    $enc_name,
    'AES-256-CBC',
    $encryption_key,
    0,
    $iv
));

Аутентифицированное шифрование

Вы можете дальнейшее улучшение целостности сгенерированного зашифрованного текста путем добавления подписи, сгенерированной из секретного ключа (отличного от ключа шифрования), и зашифрованного текста. Перед расшифровкой зашифрованного текста подпись сначала проверяется (предпочтительно методом сравнения с постоянным временем).

Пример

// generate once, keep safe
$auth_key = openssl_random_pseudo_bytes(32, $strong);

// authentication
$auth = hash_hmac('sha256', $enc_name, $auth_key, true);
$auth_enc_name = $auth . $enc_name;

// verification
$auth = substr($auth_enc_name, 0, 32);
$enc_name = substr($auth_enc_name, 32);
$actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);

if (hash_equals($auth, $actual_auth)) {
    // perform decryption
}

См. также: hash_equals()

Хеширование

Следует по возможности избегать хранения обратимого пароля в вашей базе данных; вы только хотите проверить пароль, а не знать его содержимое. Если пользователь теряет свой пароль, лучше разрешить ему сбросить его, а не отправлять ему свой оригинальный (убедитесь, что сброс пароля может быть выполнен только в течение ограниченного времени).

Применение хэш-функции является односторонней операцией; впоследствии ее можно безопасно использовать для проверки, не раскрывая исходные данные; для паролей метод грубой силы является приемлемым подходом для его раскрытия из-за его относительно короткого длина и плохой выбор пароля многими людьми.

Алгоритмы хэширования, такие как MD5 или SHA1, были созданы для проверки содержимого файла на соответствие известному значению хэша. Они значительно оптимизированы, чтобы сделать эту проверку как можно более быстрой, сохраняя при этом точность. Учитывая их относительно ограниченное пространство для вывода, было легко создать базу данных с известными паролями и их соответствующими хэш-выходами, таблицами rainbow.

Добавление соли в пароль перед хэшированием приведет к появлению радуги таблица бесполезна, но последние достижения в области аппаратного обеспечения сделали поиск методом грубой силы жизнеспособным подходом. Вот почему вам нужен алгоритм хеширования, который намеренно медленный и просто невозможно оптимизировать. Он также должен быть в состоянии увеличить нагрузку на более быстрое оборудование, не влияя на возможность проверки существующих хэшей паролей, чтобы сделать его надежным в будущем.

В настоящее время доступны два популярных варианта:

  1. PBKDF2 (Функция Получения ключа на основе пароля v2)
  2. bcrypt (он же Иглобрюх)

В этом ответе будет использован пример с bcrypt.

Поколение

Хэш пароля может быть сгенерирован следующим образом:

$password = 'my password';
$random = openssl_random_pseudo_bytes(18);
$salt = sprintf('$2y$%02d$%s',
    13, // 2^n cost factor
    substr(strtr(base64_encode($random), '+', '.'), 0, 22)
);

$hash = crypt($password, $salt);

Соль образуется с openssl_random_pseudo_bytes() для формирования случайного большого двоичного объекта данных, который затем проходит через base64_encode() и strtr(), чтобы соответствовать требуемому алфавиту [A-Za-z0-9/.].

В crypt() функция выполняет хэширование на основе алгоритма ($2y$ для Blowfish), коэффициент стоимости (коэффициент 13 занимает примерно 0,40 с на машине с частотой 3 ГГц) и соль из 22 символов.

Проверка достоверности

После того, как вы выбрали строку, содержащую информацию о пользователе, вы подтверждаете пароль следующим образом:

$given_password = $_POST['password']; // the submitted password
$db_hash = $row['Password']; // field with the password hash

$given_hash = crypt($given_password, $db_hash);

if (isEqual($given_hash, $db_hash)) {
    // user password verified
}

// constant time string compare
function isEqual($str1, $str2)
{
    $n1 = strlen($str1);
    if (strlen($str2) != $n1) {
        return false;
    }
    for ($i = 0, $diff = 0; $i != $n1; ++$i) {
        $diff |= ord($str1[$i]) ^ ord($str2[$i]);
    }
    return !$diff;
}

Чтобы проверить пароль, вы снова вызываете crypt(), но передаете ранее вычисленный хэш в качестве значения соли. Возвращаемое значение дает тот же хэш, если указанный пароль совпадает с хэшем. Чтобы проверить хэш, часто требуется рекомендуется использовать функцию сравнения с постоянным временем, чтобы избежать временных атак.

Хэширование паролей с помощью PHP 5.5

PHP 5.5 представил функции хеширования паролей , которые вы можете использовать для упрощения описанного выше метода хеширования:

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);

И проверка:

if (password_verify($given_password, $db_hash)) {
    // password valid
}

См. также: password_hash(), password_verify()

 271
Author: Ja͢ck, 2015-05-11 10:44:57

Я думаю, что на этот вопрос уже давали ответ... но в любом случае, если вы хотите зашифровать/расшифровать данные, вы не можете использовать SHA256

//Key
$key = 'SuperSecretKey';

//To Encrypt:
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, 'I want to encrypt this', MCRYPT_MODE_ECB);

//To Decrypt:
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB);
 20
Author: romo, 2012-06-06 14:37:22

Предыстория ответа и объяснение

Чтобы понять этот вопрос, вы должны сначала понять, что такое SHA256. SHA256 - это Криптографическая хэш-функция. Криптографическая хэш-функция - это односторонняя функция, вывод которой криптографически безопасен. Это означает, что легко вычислить хэш (эквивалентно шифрованию данных), но трудно получить исходные входные данные с помощью хэша (эквивалентно расшифровке данных). Поскольку использование криптографической хэш-функции означает расшифровку вычислительно неосуществимо, поэтому вы не можете выполнить расшифровку с помощью SHA256.

То, что вы хотите использовать, - это двусторонняя функция, но более конкретно, блочный шифр . Функция, которая позволяет как шифровать, так и расшифровывать данные. Функции mcrypt_encrypt и mcrypt_decrypt по умолчанию используют алгоритм Blowfish. Использование PHP mcrypt можно найти в этом руководстве . Также существует список определений шифров для выбора используемого mcrypt шифра. Вики на Иглобрюх можно найти в Википедии. Блочный шифр шифрует входные данные в блоках известного размера и положения с помощью известного ключа, чтобы впоследствии данные можно было расшифровать с помощью ключа. Это то, что SHA256 не может вам предоставить.

Код

$key = 'ThisIsTheCipherKey';

$ciphertext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, 'This is plaintext.', MCRYPT_MODE_CFB);

$plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB);
 14
Author: cytinus, 2014-08-06 12:15:51

Вот пример использования openssl_encrypt

//Encryption:
$textToEncrypt = "My Text to Encrypt";
$encryptionMethod = "AES-256-CBC";
$secretHash = "encryptionhash";
$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$encryptedText = openssl_encrypt($textToEncrypt,$encryptionMethod,$secretHash, 0, $iv);

//Decryption:
$decryptedText = openssl_decrypt($encryptedText, $encryptionMethod, $secretHash, 0, $iv);
print "My Decrypted Text: ". $decryptedText;
 7
Author: Vivek, 2016-05-19 20:28:31

Мне потребовалось довольно много времени, чтобы понять, как не получить false при использовании openssl_decrypt() и заставить работать шифрование и дешифрование.

    // cryptographic key of a binary string 16 bytes long (because AES-128 has a key size of 16 bytes)
    $encryption_key = '58adf8c78efef9570c447295008e2e6e'; // example
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($plaintext, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv);
    $encrypted = $encrypted . ':' . base64_encode($iv);

    // decrypt to get again $plaintext
    $parts = explode(':', $encrypted);
    $decrypted = openssl_decrypt($parts[0], 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, base64_decode($parts[1])); 

Если вы хотите передать зашифрованную строку по URL-адресу, вам необходимо URL-кодировать строку:

    $encrypted = urlencode($encrypted);

Чтобы лучше понять, что происходит, прочитайте:

Для генерации ключей длиной 16 байт вы можете использовать:

    $bytes = openssl_random_pseudo_bytes(16);
    $hex = bin2hex($bytes);

Для просмотра сообщений об ошибках openssl вы можете использовать: echo openssl_error_string();

Надеюсь, это поможет.

 0
Author: Kai Noack, 2017-09-08 21:26:30
     function my_simple_crypt( $string, $action = 'e' ) {
        // you may change these values to your own
        $secret_key = 'my_simple_secret_key';
        $secret_iv = 'my_simple_secret_iv';

        $output = false;
        $encrypt_method = "AES-256-CBC";
        $key = hash( 'sha256', $secret_key );
        $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

        if( $action == 'e' ) {
            $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
        }
        else if( $action == 'd' ){
            $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
        }

        return $output;
    }
 0
Author: gaurav daxini, 2018-04-20 07:12:05