Что такое openssl iv и зачем мне ключ и iv?

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

В нашей базе данных мы используем шифрование aes, которое использует 128-битный ключ, поэтому я знаю, что это за ключ, но я не знаю, что такое openssl iv? И зачем мне ключ и iv.

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

Очевидно, я изменю его так, чтобы ключ хранился в другом месте.

function encrypt_decrypt($action, $string) {
    $output = false;

    $encrypt_method = "AES-256-CBC";
    $secret_key = 'This is my secret key';
    $secret_iv = 'This is my secret iv';

    // hash
    $key = hash('sha256', $secret_key);

    // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
    $iv = substr(hash('sha256', $secret_iv), 0, 16);

    if( $action == 'encrypt' ) {
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
        $output = base64_encode($output);
    }
    else if( $action == 'decrypt' ){
        $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
    }

    return $output;
}

$plain_txt = "This is my plain text";
echo "Plain Text = $plain_txt\n";

$encrypted_txt = encrypt_decrypt('encrypt', $plain_txt);
echo "Encrypted Text = $encrypted_txt\n";

$decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt);
echo "Decrypted Text = $decrypted_txt\n";

if( $plain_txt === $decrypted_txt ) echo "SUCCESS";
else echo "FAILED";

echo "\n";

person Thomas Williams    schedule 09.09.2016    source источник
comment
iv = вектор инициализации. Было бы разумно потратить время на понимание шифрования, прежде чем пытаться его внедрить.   -  person dbugger    schedule 09.09.2016
comment
Я понимаю, как работает шифрование mysql с использованием AES_ENCRYPT, но это для mysql. Это только для строк php, которые нуждаются в шифровании   -  person Thomas Williams    schedule 09.09.2016
comment
@ThomasWilliams По умолчанию MySQL AES_ENCRYPT использует режим ECB, а не CBC. Использование ECB - вот почему MySQL не требует, чтобы вы вводили ему IV.   -  person vcsjones    schedule 09.09.2016
comment
Если вы не понимаете этих вещей, вам необходимо использовать криптографические API более высокого уровня, которые правильно заботятся об этих деталях.   -  person President James K. Polk    schedule 09.09.2016


Ответы (4)


Вектор инициализации является частью того, что заставляет AES в режиме CBC (Cipher Block Chaining) работать - IV не являются уникальными для OpenSSL. CBC работает путем XOR предыдущего блока с текущим блоком. Самый первый блок не имеет предыдущего, поэтому IV служит этой цели.

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

Я бы рекомендовал потратить немного времени на лучшие практики для векторов инициализации CBC. Неправильное их использование может ослабить общую безопасность AES. Краткое объяснение:

  • IV должны быть случайными и генерироваться CSPRNG.
  • IV не следует использовать повторно. То есть не шифруйте открытый текст «A» и открытый текст «B» одним и тем же IV. У каждой записи должен быть свой IV.
  • IV не секрет, как ключ. Он может быть сохранен в виде открытого текста вместе с зашифрованным текстом.

Также имейте в виду, что этот совет относится только к AES-CBC. Если вы когда-нибудь исследуете другие режимы AES, такие как GCM, это не применимо.

person vcsjones    schedule 09.09.2016
comment
одно крошечное дополнение: хранится вместе с зашифрованным текстом ... некоторые люди склонны просто помещать его перед зашифрованным текстом и не маркировать его как IV ... иногда стоит попытаться просто увидеть размер первого блока битов зашифрованный текст в качестве кандидата на IV, который только что хранился ... - person DarkSquirrel42; 09.09.2016
comment
Я собираюсь использовать это для шифрования строк для URL-адреса, например www.somesite.com?a=mystring. Если iv генерируется случайным образом, как вы собираетесь его расшифровать. Я согласен, мне нужно еще прочитать об этом, но мои поиски в Google только что привели к еще большей путанице. Я действительно много гуглил, прежде чем задавать вопрос. - person Thomas Williams; 09.09.2016
comment
Затем используйте www.somesite.com?a=encypyptedstring&iv=theiv. - person vcsjones; 09.09.2016
comment
Так что я прав, думая, что iv похож на строку bcrypt, которая находится в начале каждого хэша bcrypt, например, $ 2y $ 10 $. Также имеет значение длина iv - person Thomas Williams; 09.09.2016
comment
@ThomasWilliams IV можно хранить где угодно. Да, вы можете поместить его перед зашифрованным текстом с разделителем, если хотите. IV в AES всегда равен размеру блока, который в случае AES составляет 128 бит или 16 байтов. - person vcsjones; 09.09.2016
comment
Спасибо, сейчас гуглю, как сделать CSPRNG - person Thomas Williams; 09.09.2016
comment
ааа, я нашел команду openssl, которая теперь читает это openssl_random_pseudo_bytes. - person Thomas Williams; 09.09.2016
comment
@ThomasWilliams При всем уважении, вы не должны реализовывать это самостоятельно. Незнание предмета означает, что вы, скорее всего, допустите ошибку при реализации и оставите брешь в своей безопасности. Всего два цента. Найдите библиотеку более высокого уровня. - person Luke Joshua Park; 09.09.2016
comment
У меня все работает. Мое незнание было связано с openssl. Однако я довольно давно занимаюсь программированием на c ++ и php. Я много читал об этом с тех пор, как задал вопрос, и у меня все это реализовано и работает. Я однажды написал свой собственный алгоритм шифрования на C ++, но лучше использовать что-то проверенное и проверенное, чем ваш собственный код. - person Thomas Williams; 10.09.2016

Допустим, у двух пользователей есть пароль princess, и вы закодируете их ключом some-key, у них обоих будет одинаковый зашифрованный результат:

| User       | Encrypted password    |
|------------|-----------------------|
| a          | sN7vIFg=              |
| b          | sN7vIFg=              |

Это означает, что если кто-то с помощью других средств выяснит, что настоящий пароль пользователя a - «princess», а его зашифрованный пароль - «sN7vIFg =», то любой пользователь с зашифрованным паролем «sN7vIFg =» может считаться имеющим пароль «princess» ".

Однако, если вы используете случайный IV для каждого, тогда будет сложнее угадать базовые пароли, если у вас есть доступ к зашифрованным данным.

| User       | Encrypted password    | IV             |
|------------|-----------------------|----------------|
| a          | sN7vIFg=              | h²ÓIF8]h%L     |
| b          | BjZAzrA=              | VÂøíiøÚØò▓     |

Теперь, даже если у кого-то есть доступ к приведенным выше данным, он не может определить, что у пользователей a и b одинаковый пароль.

См. Также "Настоящая соль" - это то же самое, что "векторы инициализации" ?.

person alberto56    schedule 19.11.2019

Я думаю, вы, возможно, перепутали «хешированный ключ» и «iv» (Бог знает, что я это сделал, когда запускал криптовалюту). хешированный ключ - это именно то, что вы сделали. Для iv вы должны использовать разные случайные данные каждый раз, когда шифрование выполняется с одним и тем же ключом. (мой фон: мне пришлось создать обработчик безопасного сеанса pdo, который шифрует / дешифрует данные сеанса, поэтому я закончил реализацию AES-256-CBC с использованием расширения openssl)

просто небольшая подсказка, если кто-нибудь сюда попадет.

// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);

это неправильный способ создания iv + нет необходимости в secret_iv, потому что iv должен быть настолько случайным, насколько это возможно. Не относитесь к нему (и не понимайте его) так же, как к хешированию.

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

$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));

Он будет в двоичном формате, поэтому, если он вам нужен в шестнадцатеричном формате, используйте bin2hex ($ iv). Если вам нужно сохранить сгенерированный iv в mysql, я сохраню его в необработанном формате (тип поля varbinary, binary также работает).

Еще кое-что. У вас есть тег $ options, установленный в 0 как в openssl_encrypt, так и в _decrypt, что означает, что «если установлено значение true, будут возвращены необработанные выходные данные, в противном случае возвращаемое значение будет закодировано в base64».

person ConfusedAmish    schedule 23.05.2017
comment
люблю объяснение, воссоздающее $ iv - person Pancho; 17.08.2017
comment
При помещении его в качестве префикса к зашифрованному сообщению в файле, в каком формате должен быть сгенерированный IV? - person ClemC; 14.07.2019

Обычно я настраиваю что-то вроде этого:

    // PHP Function to encrypt
function encrypt_AES_CBC ($plaintext) {
    $method = "aes-256-cbc";
    $key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
    $bkey = hex2bin($key);
    $iv = hex2bin(md5(microtime().rand()));
    $data = openssl_encrypt($plaintext, $method, $bkey, OPENSSL_RAW_DATA, $iv);
    return base64_encode($iv.$data);
}
// PHP Function to decrypt
function decrypt_AES_CBC ($encryptedText) {
    $method = "aes-256-cbc";
    $key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
    $bkey = hex2bin($key);
    $decoded = base64_decode($encryptedText);
    $iv = substr($decoded, 0, 16);
    $data = substr($decoded, 16);
    return openssl_decrypt( $data, $method, $bkey, OPENSSL_RAW_DATA, $iv );
}

Я создал плагин FileMaker (acfplugin), который может генерировать этот пример кода для заданного словесного ключа.

person olekeh    schedule 21.03.2021