php aes 256 cbc
Выбор наиболее криптостойкого режима симметричного шифрования с алгоритмом AES-256 (CBC/CTR)
Я на php улучшаю, ранее разработанную мной, систему шифрованных команд, которая является частью системы аутентификации пользователей, суть которой в следующем.
1 Сервер создаёт и отправляет пользователю на email ссылку, в которой содержатся зашифрованные командные данными (data) и вектором инициализации ( IV ).
2 Сервер, при получении этих данных в GET-запросе, расшифровывает данные, проверяет на валидность, и если всё верно (данные соответствуют некой структуре, данные не просрочены, команда и все данные, необходимые для выполнения указанной команды существуют, и ещё некоторые проверки, в зависимости от команды), тогда сервер предполагает, что эти данные отправил именно тот пользователь, на email которого они отправлялись и немедленно выполняет соответствующую команду (регистрация нового пользователя, подтверждение на восстановление пароля, генерация и отправка пользователю нового пароля, подтверждение на изменение email, изменение email).
3 Шифруемые командные данные могут достигать длины примерно 128 символов.
Ранее я использовал php-модуль mcrypt
Сейчас хочу использовать php-модуль openssl
Но вот я не уверен, оптимальный ли я выбрал для этого режим (CTR)?
Я много гуглил по режимам симметричного шифрования, на русских рессурсах, так как с английским у меня плохо, и понял лишь, что.
1 ECB лучше вообще не использовать, если длина данных более одного блока (256 бит = 32 символа), а у меня больше.
2 CBC уязвим из-за своей особенности дополнять последний блок.
3 CFB и CTR быстрее, чем CBC и длина зашифрованных данных меньше, и тут нет авто дополнение последнего блока, как и блоков вообще, так как это поточные алгоритмы, но ни слова про криптостойкость и про сравнение по криптостойкости с CBC.
4 Описание и сравнение GCM и XTS я вообще не нащёл.
Получил, среди прочего, вот такое:
Чем эти 3 группы друг от друга отличаются, но или хотя бы 1-ая от 2-ой? 3-яя, как я догадываюсь, это передача помимо шифрованных данных не шифрованных для аутентификации, но могу и ошибаться.
Опишите мне, достоинства и недостатки этих методов по сравнению друг с другом акцентируя внимание именно на криптостойкости?
Единственные безопасные, которые можно использовать, по рекомендации Нильза Фергюсена (Niels Ferguson), это CBC и CTR.
AES-256 CBC encrypt in php and decrypt in Java or vice-versa
The resulting ciphers are different, even though they are using the same key and IV. How is this possible?
2 Answers 2
Clearly you must use the same AES key and IV for a secure session. And they must be properly and securely communicated across clients. It does not matter at all what language the clients are written in. Your problem is not understanding the protocol for key agreement and session establishment.
The initialization vector is not a protected value; i.e., you are not encrypting it when communicating between clients. It must be packaged in cleartext with encrypted AES key (which you derive from some key agreement protocol).
CMS uses a KeyTransRecipientInfo to deliver this information. TLS also defines IV establishment followings its handshake. I would highly suggest following the CMS implementation instead of something contrived and almost guaranteed to contain security bugs.
Update
It is now clear that you are confused why the resulting ciphertexts are not deterministic. That is because the Java implementation is defaulting to a 128-bit encryption and has been supplied a 128-bit key, but the PHP code is requesting 256-bit strength encryption and only being supplied the same 128-bit key. Therefore, PHP must be padding the key.
Update 2
Based on your below comments, here is an example of using Java to generate a 256-bit key:
openssl_encrypt
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
openssl_encrypt — Шифрует данные
Описание
Шифрует данные с заданным шифром и ключом и возвращает необработанную строку, либо строку кодированную в base64
Список параметров
Данные для шифрования.
Кодовая фраза. Если кодовая фраза укорочена, чем ожидалось, она автоматически дополняется символами NUL ; если кодовая фраза длиннее, чем ожидалось, она автоматически усекается.
Ненулевой инициализирующий вектор.
Тег аутентификации, передаваемый по ссылке, в режиме шифрования AEAD (GCM или CCM).
Дополнительные аутентификационные данные.
Возвращаемые значения
Возвращает зашифрованную строку или false в случае возникновения ошибки.
Ошибки
Список изменений
Примеры
Пример #1 Пример шифрования AES с аутентификацией в режиме GCM в PHP 7.1+
Пример #2 Пример шифрования AES с аутентификацией до PHP 7.1
Смотрите также
User Contributed Notes 24 notes
There’s a lot of confusion plus some false guidance here on the openssl library.
The basic tips are:
aes-256-ctr is arguably the best choice for cipher algorithm as of 2016. This avoids potential security issues (so-called padding oracle attacks) and bloat from algorithms that pad data to a certain block size. aes-256-gcm is preferable, but not usable until the openssl library is enhanced, which is due in PHP 7.1
Use different random data for the initialisation vector each time encryption is made with the same key. mcrypt_create_iv() is one choice for random data. AES uses 16 byte blocks, so you need 16 bytes for the iv.
Join the iv data to the encrypted result and extract the iv data again when decrypting.
Pass OPENSSL_RAW_DATA for the flags and encode the result if necessary after adding in the iv data.
Hash the chosen encryption key (the password parameter) using openssl_digest() with a hash function such as sha256, and use the hashed value for the password parameter.
There’s a simple Cryptor class on GitHub called php-openssl-cryptor that demonstrates encryption/decryption and hashing with openssl, along with how to produce and consume the data in base64 and hex as well as binary. It should lay the foundations for better understanding and making effective use of openssl with PHP.
Hopefully it will help anyone looking to get started with this powerful library.
Many users give up with handilng problem when openssl command line tool cant decrypt php openssl encrypted file which is encrypted with openssl_encrypt function.
For example how beginner is encrypting data:
?>
And then how beginner is trying to decrypt data from command line:
Or even if he/she determinates that openssl_encrypt output was base64 and tries:
Or even if he determinates that base64 encoded file is represented in one line and tries:
Or even if he determinates that IV is needed and adds some string iv as encryption function`s fourth parameter and than adds hex representation of iv as parameter in openssl command line :
All these troubles will have no result in any case.
BECAUSE THE PASSWORD PARAMETER DOCUMENTED HERE IS NOT THE PASSWORD.
It means that the password parameter of the function is not the same string used as [-pass pass:] parameter with openssl cmd tool for file encryption decryption.
And now how to correctly encrypt data with php openssl_encrypt and how to correctly decrypt it from openssl command line tool.
$iv = «1234567812345678» ;
$pass = ‘1234567812345678’ ;
$method = ‘aes-128-cbc’ ;
?>
IV and Key parameteres passed to openssl command line must be in hex representation of string.
The correct command for decrypting is:
As it has no salt has no padding and by setting functions third parameter we have no more base64 encoded file to decode. The command will echo that it works.
if (options & OPENSSL_RAW_DATA) <
outbuf[outlen] = ‘\0’;
RETVAL_STRINGL((char *)outbuf, outlen, 0);
> else <
int base64_str_len;
char *base64_str;
base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len);
efree(outbuf);
RETVAL_STRINGL(base64_str, base64_str_len, 0);
>
So as we can see here, OPENSSL_ZERO_PADDING has a direct impact on the OpenSSL context. EVP_CIPHER_CTX_set_padding() enables or disables padding (enabled by default). So, OPENSSL_ZERO_PADDING disables padding for the context, which means that you will have to manually apply your own padding out to the block size. Without using OPENSSL_ZERO_PADDING, you will automatically get PKCS#7 padding.
OPENSSL_RAW_DATA does not affect the OpenSSL context but has an impact on the format of the data returned to the caller. When OPENSSL_RAW_DATA is specified, the returned data is returned as-is. When it is not specified, Base64 encoded data is returned to the caller.
PHP lacks a build-in function to encrypt and decrypt large files. `openssl_encrypt()` can be used to encrypt strings, but loading a huge file into memory is a bad idea.
So we have to write a userland function doing that. This example uses the symmetric AES-128-CBC algorithm to encrypt smaller chunks of a large file and writes them into another file.
To decrypt files that have been encrypted with the above function you can use this function.
Please note that at the time of writing this, there is an important and naive security vulnerability in «Example #2 AES Authenticated Encryption example for PHP 5.6+».
You MUST include the IV when calculating the HMAC. Otherwise, somebody could alter the IV during transport, thereby changing the decrypted message while maintaining HMAC integrity. An absolute disaster.
To fix the example, the HMAC should be calculated like this:
How to migrate from mcrypt to openssl with backward compatibility.
In my case I used Blowfish in ECB mode. The task was to decrypt data with openssl_decrypt, encrypted by mcrypt_encrypt and vice versa. It was obvious for a first sight. But in fact openssl_encrypt and mcrypt_encript give different results in most cases.
Investigating the web I found out that the reason is in different padding methods. And for some reasons openssl_encrypt behave the same strange way with OPENSSL_ZERO_PADDING and OPENSSL_NO_PADDING options: it returns FALSE if encrypted string doesn’t divide to the block size. To solve the problem you have to pad your string with NULs by yourself.
The second question was the key length. Both functions give the same result if the key length is between 16 and 56 bytes. And I managed to find that if your key is shorter than 16 bytes, you just have to repeat it appropriate number of times.
And finally the code follows which works the same way on openssl and mcrypt libraries.
$data = ‘my secret message’ ;
$key = ‘dontsay’ ;
string(32) «SWBMedXJIxuA9FcMOqCqomk0E5nFq6wv»
string(24) «my secret message\000\000\000\000\000\000\000»
AES-256-CBC encrypted with PHP and decrypt in Java
I am in a situation where a JSON is encrypted in PHP’s openssl_encrypt and needs to be decrypted in JAVA.
Now, the problem is when I try to do same things in Java it doesn’t work 🙁
I have already visited similar question like
and list continues. but no luck there
btw, this is how encryption is done in PHP
and yes, I forgot to mention that my JRE is already at UnlimitedJCEPolicy and I can’t change PHP code.
I am totally stuck at this point and can’t move forward. Please help out.
EDIT#1
Above snippet seems to be working with openssl_encrypt
EDIT#2
I am not sure if this is correct, but following is what I have done and encryption-decryption on both side are working fine.
Encrypt in PHP, Decrypt in JAVA use AES/CBC/NoPadding
Encrypt in JAVA, Decrypt in PHP use AES/CBC/PKCS5Padding
2 Answers 2
I won’t provide a complete solution, but there are a few differences you should take care of
Encoding:
are you sure the IV and data are the same in Java and PHP (The IV is string?)? If the data are encrypted, they should be treated as a byte array, not string. Just REALLY make sure they are THE SAME (print hex/base64 in php and java)
Simply treat data and iv as byte[]
Key generation according to the openssl
you should generate a 256 bit key usging the EVP_BytesToKey function (it’s a key derivation function used by openssl).
PHP AES encrypt / decrypt
I found an example for en/decoding strings in PHP. At first it looks very good but it wont work 🙁
Does anyone know what the problem is?
10 Answers 10
Please use an existing secure PHP encryption library
It’s generally a bad idea to write your own cryptography unless you have experience breaking other peoples’ cryptography implementations.
None of the examples here authenticate the ciphertext, which leaves them vulnerable to bit-rewriting attacks.
If you can install PECL extensions, libsodium is even better
Then to test it out:
This can be used in any situation where you are passing data to the client (e.g. encrypted cookies for sessions without server-side storage, encrypted URL parameters, etc.) with a reasonably high degree of certainty that the end user cannot decipher or reliably tamper with it.
Since libsodium is cross-platform, this also makes it easier to communicate with PHP from, e.g. Java applets or native mobile apps.
Note: If you specifically need to add encrypted cookies powered by libsodium to your app, my employer Paragon Initiative Enterprises is developing a library called Halite that does all of this for you.
If you don’t want to use a heavy dependency for something solvable in 15 lines of code, use the built in OpenSSL functions. Most PHP installations come with OpenSSL, which provides fast, compatible and secure AES encryption in PHP. Well, it’s secure as long as you’re following the best practices.
The following code:
IV is a public information and needs to be random for each message. The hash ensures that the data hasn’t been tampered with.
edit: Updated to use hash_equals and added IV to the hash.