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

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

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

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

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

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

Ответ 1

Предисловие

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

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

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

  • Поля Fname, Lname и Email будут зашифрованы с использованием симметричного шифра, предоставленного OpenSSL,
  • В поле IV будет сохранен вектор инициализации, используемый для шифрования. Требования к хранению зависят от используемого шифрования и используемого режима; об этом позже.
  • Поле 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()

хэширования

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

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

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

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

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

  • PBKDF2 (функция деривации пароля на основе пароля v2)
  • bcrypt (aka 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 с 3GHz) и соль 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()

Ответ 2

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

Ответ 3

Ответ Фон и пояснение

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

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

Ответ 4

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

Ответ 5

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

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