it-roy-ru.com

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

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

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

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

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

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

106
Randel Ramirez

Предисловие

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

- 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.

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

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

  1. PBKDF2 (функция определения ключа на основе пароля v2)
  2. bcrypt (он же Blowfish)

Этот ответ будет использовать пример с 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 символа.

Validation

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

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

282
Ja͢ck

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

Справочная информация и объяснение

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

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

Вот пример использования 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;
8
Vivek
     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;
    }
1
gauravbhai daxini

Мне потребовалось много времени, чтобы понять, как не получить 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();

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

0
Kai Noack