mcrypt_encrypt

(PHP 4 >= 4.0.2, PHP 5, PHP 7 < 7.2.0, PECL mcrypt >= 1.0.0)

mcrypt_encryptШифрует текст с заданными параметрами

Внимание

Функция УСТАРЕЛА с PHP 7.1.0, а в PHP 7.2.0 функцию УДАЛИЛИ. Пользоваться функцией настоятельно не рекомендуют.

Описание

mcrypt_encrypt(
    string $cipher,
    string $key,
    string $data,
    string $mode,
    string $iv = ?
): string|false

Шифрует данные.

Список параметров

cipher

Одна из констант MCRYPT_ciphername или название алгоритма в виде строки.

key

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

data

Данные, которые будут зашифрованы с помощью шифра cipher и режима mode. Если размер данных не кратен размеру блока, то они будут дополнены символами '\0'.

Размер возвращаемого текста может быть больше размера исходных данных data.

mode

Одна из констант MCRYPT_MODE_modename, либо одна из следующих строк: "ecb", "cbc", "cfb", "ofb", "nofb" и "stream".

iv

Указывают для инициализации в режимах CBC, CFB, OFB, а также в некоторых алгоритмах в режиме STREAM. Если переданный IV размер не поддерживается режимом сцепления или IV не был передан, а режим сцепления его требует, функция сгенерирует предупреждение об ошибке и вернёт false.

Возвращаемые значения

Возвращает строку с зашифрованными данными или false, если возникла ошибка.

Примеры

Пример #1 Пример использования mcrypt_encrypt()

<?php
# --- ШИФРОВАНИЕ ---

# ключ должен представлять собой случайную бинарную строку.
# Для преобразовангия строки в ключ используйте scrypt, bcrypt или PBKDF2
# Ключ задаётся в виде строки шестнадцатеричных чисел
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");

# Показываем длину ключа.
# Длина ключа должна быть 16, 24 или 32 байт для AES-128, 192 и 256 соответственно
$key_size = strlen($key);
echo
"Длина ключа: " . $key_size . "\n";

$plaintext = "This string was AES-256 / CBC / ZeroBytePadding encrypted.";

# Создаём случайный инициализирующий вектор используя режим CBC
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

# Создаём шифрованный текст совместимыс с AES (размер блока = 128)
# Подходит только для строк не заканчивающихся на 00h
# (потому как это символ дополнения по умолчанию)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
$plaintext, MCRYPT_MODE_CBC, $iv);

# Добавляем инициализирующий вектор в начало, чтобы он был доступен для расшифровки
$ciphertext = $iv . $ciphertext;

# перекодируем зашифрованный текст в base64
$ciphertext_base64 = base64_encode($ciphertext);

echo
$ciphertext_base64 . "\n";

# === ВНИМАНИЕ ===

# Результирующий шифрованный текст не имеет целостности или аутентичности и не
# защищён от атак padding oracle.

# --- ДЕШИФРОВКА ---

$ciphertext_dec = base64_decode($ciphertext_base64);

# Извлекаем инициализирующий вектор. Длина вектора ($iv_size) должна совпадать
# с тем, что возвращает функция mcrypt_get_iv_size()
$iv_dec = substr($ciphertext_dec, 0, $iv_size);

# Извлекаем зашифрованный текст
$ciphertext_dec = substr($ciphertext_dec, $iv_size);

# Отбрасываем завершающие символы 00h
$plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
$ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

echo
$plaintext_dec . "\n";
?>

Результат выполнения приведённого примера:

Длина ключа: 32
ENJW8mS2KaJoNB5E5CoSAAu0xARgsR1bdzFWpEn+poYw45q+73az5kYi4j+0haevext1dGrcW8Qi59txfCBV8BBj3bzRP3dFCp3CPQSJ8eU=
This string was AES-256 / CBC / ZeroBytePadding encrypted.

Смотрите также

  • mcrypt_decrypt() - Расшифровывает данные с заданными параметрами
  • mcrypt_module_open() - Открывает модуль шифрования с использованием указанных алгоритма и режима

Добавить

Примечания пользователей 2 notes

up
63
scott at paragonie dot com
9 years ago
If you're writing code to encrypt/encrypt data in 2015, you should use openssl_encrypt() and openssl_decrypt(). The underlying library (libmcrypt) has been abandoned since 2007, and performs far worse than OpenSSL (which leverages AES-NI on modern processors and is cache-timing safe).

Also, MCRYPT_RIJNDAEL_256 is not AES-256, it's a different variant of the Rijndael block cipher. If you want AES-256 in mcrypt, you have to use MCRYPT_RIJNDAEL_128 with a 32-byte key. OpenSSL makes it more obvious which mode you are using (i.e. 'aes-128-cbc' vs 'aes-256-ctr').

OpenSSL also uses PKCS7 padding with CBC mode rather than mcrypt's NULL byte padding. Thus, mcrypt is more likely to make your code vulnerable to padding oracle attacks than OpenSSL.

Finally, if you are not authenticating your ciphertexts (Encrypt Then MAC), you're doing it wrong.

Further reading:

https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly

https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong
up
24
jesse at pctest dot com
20 years ago
Solving 3DES incompatibilities with .NET's TripleDESCryptoServiceProvider

mcrypt's 3DES only accepts 192 bit keys, but Microsoft's .NET and many other tools accept both 128 and 192 bit keys.
If your key is too short, mcrypt will 'helpfully' pad null characters onto the end, but .NET refuses to use a key where the last third is all null (this is a Bad Key). This prevents you from emulating mcrypt's "short key" behaviour in .NET.

How to reconcile this? A little DES theory is in order
3DES runs the DES algorithm three times, using each third of your 192 bit key as the 64 bit DES key

Encrypt Key1 -> Decrypt Key2 -> Encrypt Key3

and both .NET and PHP's mcrypt do this the same way.
The problem arises in short key mode on .NET, since 128 bits is only two 64 bit DES keys
The algorithm that they use then is:

Encrypt Key1 -> Decrypt Key2 -> Encrypt Key1

mcrypt does not have this mode of operation natively.
but before you go and start running DES three times yourself, here's a Quick Fix
<?php
$my_key
= "12345678abcdefgh"; // a 128 bit (16 byte) key
$my_key .= substr($my_key,0,8); // append the first 8 bytes onto the end
$secret = mcrypt_encrypt(MCRYPT_3DES, $my_key, $data, MCRYPT_MODE_CBC, $iv); //CBC is the default mode in .NET
?>

And, like magic, it works.

There's one more caveat: Data padding
mcrypt always pads data will the null character
but .NET has two padding modes: "Zeros" and "PKCS7"
Zeros is identical to the mcrypt scheme, but PKCS7 is the default.
PKCS7 isn't much more complex, though:
instead of nulls, it appends the total number of padding bytes (which means, for 3DES, it can be a value from 0x01 to 0x07)
if your plaintext is "ABC", it will be padded into:
0x41 0x42 0x43 0x05 0x05 0x05 0x05 0x05

You can remove these from a decrypted string in PHP by counting the number of times that last character appears, and if it matches it's ordinal value, truncating the string by that many characters:
<?php
$block
= mcrypt_get_block_size('tripledes', 'cbc');
$packing = ord($text{strlen($text) - 1});
if(
$packing and ($packing < $block)){
for(
$P = strlen($text) - 1; $P >= strlen($text) - $packing; $P--){
if(
ord($text{$P}) != $packing){
$packing = 0;
}
}
}
$text = substr($text,0,strlen($text) - $packing);
?>

And to pad a string that you intend to decrypt with .NET, just add the chr() value of the number of padding bytes:
<?php
$block
= mcrypt_get_block_size('tripledes', 'cbc');
$len = strlen($dat);
$padding = $block - ($len % $block);
$dat .= str_repeat(chr($padding),$padding);
?>

That's all there is to it.
Knowing this, you can encrypt, decrypt, and duplicate exactly any .NET 3DES behaviour in PHP.
To Top