Как вы шифруете и дешифруете строку PHP?

225

Я имею в виду:

Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)

Может быть что-то вроде:

"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
  • В PHP, как вы можете это сделать?

Попытка использовать Crypt_Blowfish, но это не сработало для меня.

夏 期 劇場
источник
35
@ Rogue Он не хочет хеш, он хочет симметричное шифрование (как AES), он просто не знает, как он называется. (А теперь он делает :))
Паташу
насколько безопасным это должно быть?
3
@ 夏 期 劇場, вы не «солите» симметричное шифрование, вы используете ключ. Ключ должен храниться в секрете. Соль может быть общедоступной без ущерба для безопасности (если соль у всех разная), и этот термин используется в хэшировании паролей.
Паташу
2
Вам нужен Salt (закрытый ключ), открытый ключ и алгоритм шифрования, такой как AES-256: wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy
8
@CristianFlorea Автор этого поста использует термины, которые просто не имеют ни малейшего смысла в контексте симметричного шифрования. В AES нет открытого ключа и нет соли. Есть один ключ; это должно быть в тайне. В некоторых режимах работы существует IV, который не должен быть секретным, но IV не является солью (в зависимости от режима, он может иметь совершенно разные требования) и не должен быть секретным, в то время как фактический ключ шифрования абсолютно не может быть открытым. Открытый / закрытый ключ применяется к асимметричной криптографии, но не имеет ничего общего с AES.
cpast

Ответы:

411

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

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

Вам следует избегать реализации собственной криптографии и использовать безопасную библиотеку, написанную и проверенную экспертами по криптографии.

Обновление: PHP 7.2 теперь предоставляет libsodium ! Для обеспечения максимальной безопасности обновите свои системы до версии PHP 7.2 или выше и следуйте только советам libsodium в этом ответе.

Используйте libsodium, если у вас есть доступ к PECL ( илиodium_compat, если вы хотите использовать libsodium без PECL); в противном случае ...
используйте defuse / php-encryption ; не катите свою собственную криптографию!

Обе библиотеки, указанные выше, позволяют легко и безболезненно внедрить аутентифицированное шифрование в ваши собственные библиотеки.

Если вы все еще хотите написать и развернуть свою собственную библиотеку криптографии, вопреки общепринятому мнению каждого криптографического эксперта в Интернете, вам следует предпринять следующие шаги.

Шифрование:

  1. Шифрование с использованием AES в режиме CTR. Вы также можете использовать GCM (что устраняет необходимость в отдельном MAC). Кроме того, ChaCha20 и Salsa20 (предоставляемые libsodium ) являются потоковыми шифрами и не требуют специальных режимов.
  2. Если вы не выбрали GCM выше, вы должны аутентифицировать зашифрованный текст с HMAC-SHA-256 (или, для потоковых шифров, Poly1305 - большинство API libsodium делают это за вас). MAC должен охватывать IV, а также зашифрованный текст!

Дешифрирование:

  1. Если не используется Poly1305 или GCM, пересчитайте MAC зашифрованного текста и сравните его с MAC, который был отправлен с использованием hash_equals(). Если это не удается, прервать.
  2. Расшифруйте сообщение.

Другие вопросы дизайна:

  1. Не сжимайте ничего никогда. Зашифрованный текст не сжимается; сжатие открытого текста перед шифрованием может привести к утечке информации (например, CRIME и BREACH в TLS).
  2. Убедитесь, что вы используете mb_strlen()и mb_substr(), используя '8bit'режим набора символов, чтобы предотвратить mbstring.func_overloadпроблемы.
  3. IVs должны генерироваться с использованием CSPRNG ; Если вы используете mcrypt_create_iv(), НЕ ИСПОЛЬЗУЙТЕMCRYPT_RAND !
  4. Если вы не используете конструкцию AEAD, ВСЕГДА шифруйте, а затем MAC!
  5. bin2hex(), base64_encode()И т.д. может произойти утечка информации о ваших ключей шифрования с помощью синхронизации кэша. Избегайте их, если это возможно.

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

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

Важно: когда не следует использовать шифрование

Не шифруйте пароли . Вместо этоговы хотите их хешировать , используя один из следующих алгоритмов хеширования паролей:

Никогда не используйте универсальную хеш-функцию (MD5, SHA256) для хранения пароля.

Не шифруйте параметры URL . Это неподходящий инструмент для работы.

Пример строкового шифрования PHP с помощью Libsodium

Если вы используете PHP <7.2 или у вас нет установленной библиотеки libsodium, вы можете использовать натрия_компат для достижения того же результата (хотя и медленнее).

<?php
declare(strict_types=1);

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 * @throws RangeException
 */
function safeEncrypt(string $message, string $key): string
{
    if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
        throw new RangeException('Key is not the correct size (must be 32 bytes).');
    }
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    $cipher = base64_encode(
        $nonce.
        sodium_crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
    sodium_memzero($message);
    sodium_memzero($key);
    return $cipher;
}

/**
 * Decrypt a message
 * 
 * @param string $encrypted - message encrypted with safeEncrypt()
 * @param string $key - encryption key
 * @return string
 * @throws Exception
 */
function safeDecrypt(string $encrypted, string $key): string
{   
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

    $plain = sodium_crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
    if (!is_string($plain)) {
        throw new Exception('Invalid MAC');
    }
    sodium_memzero($ciphertext);
    sodium_memzero($key);
    return $plain;
}

Затем, чтобы проверить это:

<?php
// This refers to the previous code block.
require "safeCrypto.php"; 

// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';

$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Halite - Libsodium Made Easy

Одним из проектов, над которым я работаю, является библиотека шифрования Halite , цель которой - сделать libsodium более простым и интуитивно понятным.

<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;

// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');

$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Вся криптография лежит в основе libsodium.

Пример с defuse / php-шифрованием

<?php
/**
 * This requires https://github.com/defuse/php-encryption
 * php composer.phar require defuse/php-encryption
 */

use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

require "vendor/autoload.php";

// Do this once then store it somehow:
$key = Key::createNewRandomKey();

$message = 'We are all living in a yellow submarine';

$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

Примечание : Crypto::encrypt()возвращает шестнадцатеричный код.

Управление ключами шифрования

Если у вас возникнет желание использовать «пароль», остановитесь прямо сейчас. Вам нужен случайный 128-битный ключ шифрования, а не запоминающийся пароль.

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

$storeMe = bin2hex($key);

И, по запросу, вы можете получить его так:

$key = hex2bin($storeMe);

Я настоятельно рекомендую просто хранить случайно сгенерированный ключ для долгосрочного использования вместо любого пароля в качестве ключа (или для получения ключа).

Если вы используете библиотеку Defuse:

«Но я действительно хочу использовать пароль».

Это плохая идея, но хорошо, вот как это сделать безопасно.

Сначала сгенерируйте случайный ключ и сохраните его в константе.

/**
 * Replace this with your own salt! 
 * Use bin2hex() then add \x before every 2 hex characters, like so:
 */
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");

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

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

/**
 * Get an AES key from a static password and a secret salt
 * 
 * @param string $password Your weak password here
 * @param int $keysize Number of bytes in encryption key
 */
function getKeyFromPassword($password, $keysize = 16)
{
    return hash_pbkdf2(
        'sha256',
        $password,
        MY_PBKDF2_SALT,
        100000, // Number of iterations
        $keysize,
        true
    );
}

Не просто используйте 16-значный пароль. Ваш ключ шифрования будет комично взломан.

Скотт Аркишевский
источник
3
Не шифруйте пароли , хэшируйте их password_hash()и проверяйте их password_verify().
Скотт Аркишевский
2
«Не сжимай ничего никогда». Вы имеете в виду, как HTTP, Spdy и другие протоколы? До TLS? Советов абсолютистов много?
Tiberiu-Ionuț Stan
1
@ScottArciszewski Мне нравится ваш комментарий о ключе "// Сделайте это один раз, затем сохраните его как-нибудь:" .. как-то, смеется :)) ну как насчет хранения этого 'ключа' (который является объектом) в виде простой строки, жестко закодированной? Мне нужен сам ключ, как строка. Можно ли как-нибудь получить его от этого объекта? Спасибо
Андрей
2
Спасибо, мне просто нужно было изменить одну строку, чтобы заставить ваши примеры натрия работать:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Алексей Озеров
1
Вот Это Да! +1 за упоминание не шифровать параметры URL. Мне очень понравилась статья вы предоставляете: paragonie.com/blog/2015/09/...
Lynnell Эммануэль Нери
73

Я опаздываю на вечеринку, но в поисках правильного способа сделать это я наткнулся на эту страницу, она была одной из самых популярных результатов поиска в Google, поэтому я хотел бы поделиться своим взглядом на проблему, которую я считаю актуальный на момент написания этого поста (начало 2017 года). Начиная с PHP 7.1.0, mcrypt_decryptи mcrypt_encryptбудет устаревшим, поэтому для построения будущего кода следует использовать openssl_encrypt и openssl_decrypt

Вы можете сделать что-то вроде:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

Важный : это использует режим ECB , который не является безопасным. Если вы хотите простое решение без прохождения ускоренного курса в области криптографии, не пишите его самостоятельно, просто используйте библиотеку.

Вы также можете использовать любые другие методы рубки, в зависимости от ваших потребностей безопасности. Чтобы узнать о доступных методах дробилки, см. Функцию openssl_get_cipher_methods .

Эмиль Боркони
источник
10
Спасибо, я удивлен, что этот простой и ясный ответ не более одобрен. Я бы предпочел не читать 10-страничную дискуссию на эту тему, например, главный ответ, когда все, что я хочу, - это зашифровать / расшифровать простую строку.
Лоран
4
Это не безопасный ответ. Режим ECB не должен использоваться. Если вы хотите «простой и понятный ответ», просто используйте библиотеку .
Скотт
2
@ ScottArciszewski, да, я признаю, что говорил слишком быстро, ища простой код. С тех пор я добавил IV и использую CBC в своем собственном коде, что достаточно для моего использования.
Лоран
Прочитайте это и пересмотрите . В режиме CBC злоумышленник может полностью изменить сообщение. Если сообщение является файлом, злоумышленник может перевернуть биты и открыть файл calc.exe. Риск неаутентифицированного шифрования очень велик.
Скотт
7
Все зависит от варианта использования! Есть случаи, когда это прекрасно. Например, я хочу передать параметр GET со страницы на страницу, скажем так, prod_id=123но я просто не хочу делать 123 читабельным для всех, однако даже если они смогут его прочитать, это не будет проблемой. Злоумышленник, способный заменить 123 на пользовательское значение, не причинит никакого вреда, он / она сможет получить информацию только о любом другом продукте, но обычный пользователь Joe не будет иметь понятия о том, как получить информацию для продукт 124, например. Для такого сценария это идеальное решение, а для безопасности - нет!
Эмиль Боркони
43

Что не делать

ВНИМАНИЕ:
этот ответ использует ECB . ECB - это не режим шифрования, это всего лишь строительный блок. Использование ECB, как показано в этом ответе, не обеспечивает надежного шифрования строки. Не используйте ECB в вашем коде. См ответ Скотта для хорошего решения.

Я получил это на себе. На самом деле я нашел ответ на Google и просто изменил что-то. Результат совершенно небезопасен однако.

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>
夏 期 劇場
источник
8
Вы можете использовать «MCRYPT_MODE_CBC» вместо «MCRYPT_MODE_ECB» для обеспечения большей безопасности.
Parixit
10
Рамеш, это потому, что ты получаешь необработанные зашифрованные данные. Вы можете получить более качественную версию зашифрованных данных, используя base64, например так: base64_encode(encrypt($string))- Для расшифровки:decrypt(base64_decode($encrypted))
mendezcode
82
ВНИМАНИЕ: это небезопасно . Режим ECB не должен использоваться для строк, ECB не принимает IV, это не аутентифицировано, он использует старый шифр (Blowfish) вместо AES, ключ не является двоичным и т. Д. И т. Д. Сообщество SO должно действительно прекратить шифрование upvoting / расшифровка, которая просто «работает» и запускает ответы, которые, как известно, безопасны. Если вы точно этого не знаете, не голосуйте.
Maarten Bodewes
3
Я вроде уже сделал это, mcrypt_encryptзаменив образец кода : php.net/manual/en/function.mcrypt-encrypt.php . Обратите внимание, что при рассмотрении этого вопроса в конце он, вероятно, должен иметь rtrimсимвол for "\0".
Maarten Bodewes
4
Правильный ответ - использовать что-то вроде defuse / php-encryption вместо написания собственного кода mcrypt.
Скотт Аркишевский
18

Для рамок Laravel

Если вы используете каркас Laravel, то его легче зашифровать и расшифровать с помощью внутренних функций.

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

Примечание. Обязательно установите случайную строку из 16, 24 или 32 символов в параметре ключа файла config / app.php. В противном случае зашифрованные значения не будут безопасными.

Сомнат Мулук
источник
1
Конечно, это может быть легко использовать. Но это безопасно? Как это решает проблемы в stackoverflow.com/a/30159120/781723 ? Использует ли аутентифицированное шифрование? Избегает ли он уязвимостей побочных каналов и обеспечивает проверки на равенство в постоянном времени? Использует ли он действительно случайный ключ, а не пароль / пароль? Использует ли он подходящий режим работы? Это генерирует случайные IV правильно?
DW
10

обновленный

PHP 7 готовая версия. Он использует функцию openssl_encrypt из библиотеки PHP OpenSSL .

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);
夏 期 劇場
источник
1
Это лучшая и намного более безопасная версия. Спасибо, это тоже работает, как и ожидалось.
1
как вы создаете и где храните ключ шифрования?
user2800464
7

Историческая справка: это было написано во время PHP4. Это то, что мы сейчас называем «устаревшим кодом».

Я оставил этот ответ в исторических целях - но некоторые методы в настоящее время устарели, метод шифрования DES не рекомендуется и т. Д.

Я не обновлял этот код по двум причинам: 1) я больше не работаю с методами шифрования вручную в PHP, и 2) этот код по-прежнему служит той цели, для которой он предназначен: продемонстрировать минимальную, упрощенную концепцию работы шифрования в PHP.

Если вы найдете такой же упрощенный источник «PHP-шифрование для чайников», который может заставить людей начинать с 10-20 строк кода или меньше, дайте мне знать в комментариях.

Кроме того, пожалуйста, наслаждайтесь этим Классическим Эпизодом раннего эры ответа минималистичного шифрования PHP4.


В идеале у вас есть - или вы можете получить - доступ к библиотеке PHP mcrypt, так как она, безусловно, популярна и очень полезна для самых разных задач. Вот краткий обзор различных видов шифрования и некоторых примеров кода: Методы шифрования в PHP

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

Несколько предупреждений:

1) Никогда не используйте обратимое или «симметричное» шифрование, когда подходит односторонний хэш.

2) Если данные действительно конфиденциальны, например, номера кредитных карт или социального страхования, остановитесь; вам нужно больше, чем предоставляет любой простой кусок кода, но вам нужна криптографическая библиотека, разработанная для этой цели, и значительное количество времени для исследования необходимых методов. Кроме того, программная криптография, вероятно, обеспечивает <10% безопасности конфиденциальных данных. Это все равно, что перемонтировать атомную электростанцию ​​- признать, что задача опасная и сложная, и вы не знаете, если это так. Финансовые штрафы могут быть огромными, поэтому лучше воспользоваться услугой и отчитаться за них.

3) Любое легко реализуемое шифрование, как указано здесь, может разумно защитить умеренно важную информацию, которую вы хотите сохранить от посторонних глаз, или ограничить воздействие в случае случайной / преднамеренной утечки. Но, видя, как ключ хранится в виде простого текста на веб-сервере, если они могут получить данные, они могут получить ключ дешифрования.

Как бы то ни было, получайте удовольствие :)

BrianH
источник
9
Eww, DES. Где AES?
Паташу
2
Спасибо! Но некоторые проблемы. Я получаю M�������f=�_=странные символы как зашифрованные. Разве я не могу получить простые символы? Как: 2a2ffa8f13220befbe30819047e23b2c. Кроме того, я не могу изменить ДЛИНУ $key_value(фиксированную на 8 ???) и ДЛИНУ выхода $encrypted_text? (не может ли это быть 32 или 64 или больше или больше?)
劇場 期 劇場
3
@ 夏 期 劇場 Результатом шифрования являются двоичные данные. Если вам нужно, чтобы он был удобочитаемым, используйте для него base64 или шестнадцатеричное кодирование. «Не могу ли я изменить длину значения ключа?» Различные алгоритмы симметричного шифрования имеют разные требования к значению ключа. 'и ДЛИНА ВЫХОДА ...' Длина зашифрованного текста должна быть не меньше, чем исходный текст, иначе недостаточно информации для воссоздания исходного текста. (Это применение принципа Pigeonhole.) Кстати, вы должны использовать AES вместо DES. DES легко ломается и больше не защищен.
Паташу
8
mcrypt_ecb УСТАРЕЛО с PHP 5.5.0. Использование этой функции крайне нежелательно. php.net/manual/en/function.mcrypt-ecb.php
Хафез Дивандари
1
@BrianDHall Причина, по которой это все еще получает отрицательные голоса, состоит в том, что режим ECB небезопасен (используйте CBC, CTR, GCM или Poly1305), DES является слабым (вы хотите AES, который есть MCRYPT_RIJNDAEL_128), и шифротексты должны быть аутентифицированы ( hash_hmac()проверены с hash_equals()).
Скотт Аркишевский
7

Если вы не хотите использовать библиотеку (что следует), используйте что-то вроде этого (PHP 7):

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);
АСКОН
источник
Может ли это быть заменой stackoverflow.com/a/16606352/126833 ? Я использую первый, пока мой хост не обновится до PHP 7.2.
Анджанеш
@anjanesh вы не сможете расшифровать старые данные с помощью этого (разные алгоритмы + этот также проверяет подпись)
Ascon
2
В вашем случае, вероятно, это должно сделать:define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon
Это супер!
Анжанеш
2

Это компактные методы для шифрования / дешифрования строк с помощью PHP с использованием AES256 CBC :

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

Использование:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");
Марко Конкас
источник
0

Ниже код работает в php для всей строки со специальным символом

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
Джавед
источник