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

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

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

у меня есть таблица, состоящая из этих полей (UserID,Fname,Lname,Email,Пароль)

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

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

6 ответов


предисловие

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

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

список изменений:

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

безопасность

шифр и режим

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

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

хорошим ключом шифрования является двоичный blob, который генерируется из надежного генератора случайных чисел. Рекомендуется следующий пример (>= 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);

пример

давайте зашифруем поле name, используя предыдущее $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 (он же Blowfish)

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

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

$password = 'my password';
$random = openssl_random_pseudo_bytes(18);
$salt = sprintf('y$%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() функция выполняет хэширование на основе алгоритма (y$ для Blowfish), фактор стоимости (фактор 13 принимает грубо 0.40 s на машине 3GHz) и соль 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()


Я думаю, что на это уже ответили раньше...но в любом случае, если вы хотите зашифровать/расшифровать данные, вы не можете использовать 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);

ответ фон и объяснение

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

то, что вы хотите использовать, является двухсторонней функцией, но более конкретно,Блочный Шифр. Функция, которая позволяет шифровать и расшифровывать данные. Функции mcrypt_encrypt и mcrypt_decrypt по умолчанию используйте алгоритм Blowfish. Использование PHP mcrypt можно найти в этом руководство. Список шифр определений для выбора шифра использование mcrypt также существует. Вики на Blowfish можно найти по адресу Википедия. Блочный шифр шифрует входные данные в блоках известного размера и позиции с известным ключом, так что данные могут быть расшифрованы с помощью ключа. Это то, что 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);

вот пример использования 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;

мне потребовалось довольно много времени, чтобы понять, как не получить 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-адрес, вам нужно urlencode строку:

    $encrypted = urlencode($encrypted);

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

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

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

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

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


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