Вот мой код:
<?php
$secret="This is a secret message.";
$key="Secret key.";
$iv=openssl_random_pseudo_bytes(12);
$method="aes-256-gcm";
$encrypted=openssl_encrypt($secret,$method,$key,false,$iv);
$decrypted=openssl_decrypt($encrypted,$method,$key,false,$iv);
echo $encrypted;
echo "<br>";
echo $decrypted;
?>
Я получил зашифрованное сообщение, но расшифровка не дает никакого результата или сообщения об ошибке.
Тот же код работает с другим методом, например, aes-256-cbc.
Тестирование его в моей системе (PHP 5.3.10 с внутренним возвратом OpenSSL 1.0.1) возвращает зашифрованный текст такой же длины, что и открытый текст (сообщение).
Это означает, что шифрование GCM не возвращает тег аутентификации, а только внутреннее шифрование в режиме CTR. Вероятно, это связано с тем, что оболочка PHP просто вызывает интерфейс OpenSSL напрямую и не использует следующий код:
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
который был найден в примере кода OpenSSL EVP («более высокий уровень») шифрования с использованием GCM. Другими словами, тег нужно искать отдельно.
Отдельная обработка тега действительно имеет смысл — она позволяет создать более интерактивную реализацию, которая использует меньше буферизации — но это вам здесь не поможет. Вы можете использовать AES-CBC, а затем HMAC поверх IV и зашифрованный текст, чтобы заменить режим GCM. Использование отдельного ключа для шифрования и тега аутентификации сделает эту схему несколько более безопасной.
PS Вы не можете напрямую использовать дешифрование в режиме CTR для повторного получения открытого текста из-за различий в инициализации.
Других решений пока нет …