Вопрос по php, encryption, security, cryptography, encryption-symmetric – Как зашифровать / расшифровать данные в php?

104

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

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

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

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

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

Обычно вы не хотите расшифровывать пароль! Ja͢ck
В основном вы не должны думать о шифровании на этом уровне, вы должны думать об управлении доступом, конфиденциальности, целостности и аутентификации. После этого проверьте, как вы можете достичь этого,possibly используя шифрование или безопасное хеширование. Возможно, вы захотите прочитать в PBKDF2 и bcrypt / scrypt, чтобы понять безопасное хеширование паролей и тому подобное. Maarten Bodewes
SHA - это хэш, а не шифрование. Ключевым моментом является то, что хеш не может быть возвращен к исходным данным (в любом случае, не легко). Вы, вероятно, хотитеmcrypt или если это не доступно, я бы порекомендовалphpseclib - хотя важно отметить, что любая реализация на чистом PHP всего, что включает в себя много низкоуровневой математики, будет sloooooowww ... Вот почему мне нравится phpseclib, потому что он сначала использует mcrypt, если он доступен и только возвращается к реализации PHP в качестве последнего средства. DaveRandom

Ваш Ответ

6   ответов
281
Foreword

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

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

The fields Fname, Lname and Email will be encrypted using a symmetric cipher, provided by OpenSSL, The IV field will store the initialisation vector used for encryption. The storage requirements depend on the cipher and mode used; more about this later. The Password field will be hashed using a one-way password hash, Encryption

Cipher and mode

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

Encryption key

Хороший ключ шифрования - это двоичный двоичный объект, который генерируется надежным генератором случайных чисел. Будет рекомендован следующий пример (& gt; = 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);
Example

Позвольте зашифровать поле имени, используя ранее$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
);
Storage requirements

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

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

Decryption

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

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
));
Authenticated encryption

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

Example
// 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()

Hashing

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

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

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

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

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

PBKDF2 (Password Based Key Derivation Function v2) bcrypt (aka Blowfish)

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

Generation

Хеш пароля можно сгенерировать так:

$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() еще раз, но вы передаете ранее вычисленный хеш как солт-значение. Возвращаемое значение дает тот же хеш, если данный пароль соответствует хешу. Чтобы проверить хэш, часто рекомендуется использовать функцию сравнения с постоянным временем, чтобы избежать атак по времени.

Password hashing with 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()

+1 за аутентифицированное шифрование. В этом вопросе недостаточно информации, чтобы сказать, что здесь АЕ не требуется. Конечно, трафик SQL часто проходит по сети с неизвестными свойствами безопасности, как и трафик из базы данных в хранилище. Резервное копирование и репликация тоже. Какова модель угрозы? Вопрос не говорит, и делать предположения может быть опасно.
Конечно, но это зависит от того, как он используется. Если вы публикуете библиотеку шифрования, вы не знаете, как разработчики ее реализуют. Вот почемуgithub.com/defuse/php-encryption обеспечивает аутентифицированное шифрование с симметричным ключом и не позволяет разработчикам ослаблять его, не редактируя его код.
@ Скотт Очень хорошо, я добавил пример аутентифицированного шифрования; спасибо за толчок :)
Какую длину я должен использовать, чтобы сохранить имя, фамилию, адрес электронной почты и т. Д. Для самой безопасной ставки? VARBINARY (???)
Вместо жесткого кодирования$iv_size = 16;, Я хотел бы использовать:$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC")) чтобы указать связь между размером iv, используемым с используемым шифром. Вы также можете немного расширить необходимость (или нет)pkcs7_pad()/pkcs7_unpad()или просто упростите публикацию, избавившись от них и используя "aes-256-ctr". Отличный пост @ Ja & # x362; ck
0

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

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

http://blog.turret.io/the-missing-php-aes-encryption-example/ http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-

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

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

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

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

14
Answer Background and Explanation

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

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

Code
$key = 'ThisIsTheCipherKey';

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

$plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB);
Ключи должны быть случайными байтами, или вы должны использовать функцию безопасного вывода ключа.
Лучше не использовать mcrypt, это заброшенное программное обеспечение, оно не обновлялось годами и не поддерживает стандартное заполнение PKCS # 7 (n & # xE9; e PKCS # 5), только нестандартное заполнение нулями, которое может даже не быть используется с двоичными данными. у Mcrypt было много выдающихсяbugs начиная с 2003 года. Вместо этого рассмотрите возможность использованияdefuse, это поддерживается и правильно.
Never ever используйте режим ECB. Это небезопасно, и большую часть времени на самом деле не помогает фактически зашифровать данные (а не просто зашифровать их). Увидетьexcellent Wikipedia article on the subject для дополнительной информации.
Вы также не должны использовать ECB, в этом отношении.
8

//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(), Увидетьstackoverflow.com/q/41952509/1066234 Since block ciphers such as AES require input data to be an exact multiple of the block size (16-bytes for AES) padding is necessary.
Вместоmcrypt_create_iv(), Я хотел бы использовать:openssl_random_pseudo_bytes(openssl_cipher_iv_length($encryptionMethod))Таким образом, методология работает для любого значения $ encryptionMethod и будет использовать только расширение openssl.
21

что на этот вопрос уже отвечали ... но в любом случае, если вы хотите зашифровать / расшифровать данные, вы не можете использовать 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);
MCRYPT_RIJNDAEL_256 не является стандартной функцией, вы должны использовать AES (MCRYPT_RIJNDAEL_128)
Ключи должны быть случайными байтами, или вы должны использовать функцию безопасного вывода ключа.
Вы также не должны использовать ECB, в этом отношении.
1
     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;
    }
очень просто ! Я использую его для шифрования-дешифрования сегмента URL. Спасибо

Похожие вопросы