I need a PHP function, AES256_encode($dataToEcrypt)
to encrypt the $data
into AES-256 and another one AES256_decode($encryptedData)
do the opposite. Does anyone know what code should this functions have?

- 33,610
- 16
- 89
- 206

- 287
- 1
- 3
- 4
-
Here is a good blog post explaining how to work with MCrypt library: http://code-epicenter.com/how-to-use-mcrypt-library-in-php/ – MrD Apr 09 '16 at 22:06
5 Answers
Look at the mcrypt module
AES-Rijndael example taken from here
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
# show key size use either 16, 24 or 32 byte keys for AES-128, 192
# and 256 respectively
$key_size = strlen($key);
echo "Key size: " . $key_size . "\n";
$text = "Meet me at 11 o'clock behind the monument.";
echo strlen($text) . "\n";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
echo strlen($crypttext) . "\n";
This is the decrypt function

- 18,856
- 9
- 82
- 114
-
Yes, there are even examples on this page of how to encrypt/decrypt AES: http://php.net/manual/en/ref.mcrypt.php – Justin Ethier Jul 21 '11 at 01:29
-
Thanks, this was what I was looking for. I thought RIJNDAEL and AES were two different algorithms. – mariannnn Jul 21 '11 at 01:48
-
14-1, AES-256 is **different** from `RIJNDAEL-256`. The 256 in `AES` refers to the *key* size, where the 256 in `RIJNDAEL` refers to block size. `AES-256` is `RIJNDAEL-128` when used with a 256 bit key. – ircmaxell Jun 22 '13 at 11:50
-
-1 it's bad in several ways: 1) It doesn't use AES (see ircmaxell's comment) 2) It uses ECB 3) It doesn't include a MAC and thus is vulnerable to active attacks. 4) It uses a password as key. Either use a random key, or use properly hashed password. 5) It's better to use `/dev/urandrom` to generate the iv (simply pass `MCRYPT_DEV_URANDOM` to `create_iv`) – CodesInChaos Jun 22 '13 at 13:17
-
2@CodesInChaos I've edited the answer according to your observations. Now the answer should be correct. – Fabio Jun 22 '13 at 16:00
-
2I just want to emphasize that MACs are really important if active attacks are possible. A well known attack is the ["padding oracle"](http://en.wikipedia.org/wiki/Padding_oracle_attack) where the reaction of the recipient leaks information about the plaintext allowing byte-by-byte recovery of the plaintext by querying the recipient. – CodesInChaos Jun 22 '13 at 16:12
-
1Padding is also important to note: as the mcrypt library in php only supports zero length padding. Where as most people using pkcs#5 or pkcs#7 padding. So always make sure you match the padding up if encrypting and decrypting in different platforms/places (for example: webserver vs mobile app) – DEzra Mar 18 '15 at 12:59
-
2PHP has deprecated `mcrypt` library, it will be removed from PHP version after 7.1. As such, using suggesting mcrypt makes this answer deprecated. See http://php.net/manual/en/migration71.deprecated.php – Dennis Jul 06 '17 at 18:10
I need a PHP function,
AES256_encode($dataToEcrypt)
to encrypt the$data
into AES-256 and another oneAES256_decode($encryptedData)
do the opposite. Does anyone know what code should this functions have?
There is a difference between encrypting and encoding.
Do you really need AES-256? The security of AES-256 versus AES-128 isn't that significant; you're more likely to screw up at the protocol layer than get hacked because you used a 128-bit block cipher instead of a 256-bit block cipher.
Important - Use A Library
- defuse/php-encryption
- PECL libsodium
- Halite (libsodium wrapper, now stable)
A Quick and Dirty AES-256 Implementation
If you're interested in building your own not for the sake of deploying it in production but rather for the sake of your own education, I've included a sample AES256
/**
* This is a quick and dirty proof of concept for StackOverflow.
*
* @ref http://stackoverflow.com/q/6770370/2224584
*
* Do not use this in production.
*/
abstract class ExperimentalAES256DoNotActuallyUse
{
/**
* Encrypt with AES-256-CTR + HMAC-SHA-512
*
* @param string $plaintext Your message
* @param string $encryptionKey Key for encryption
* @param string $macKey Key for calculating the MAC
* @return string
*/
public static function encrypt($plaintext, $encryptionKey, $macKey)
{
$nonce = random_bytes(16);
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-ctr',
$encryptionKey,
OPENSSL_RAW_DATA,
$nonce
);
$mac = hash_hmac('sha512', $nonce.$ciphertext, $macKey, true);
return base64_encode($mac.$nonce.$ciphertext);
}
/**
* Verify HMAC-SHA-512 then decrypt AES-256-CTR
*
* @param string $message Encrypted message
* @param string $encryptionKey Key for encryption
* @param string $macKey Key for calculating the MAC
*/
public static function decrypt($message, $encryptionKey, $macKey)
{
$decoded = base64_decode($message);
$mac = mb_substr($message, 0, 64, '8bit');
$nonce = mb_substr($message, 64, 16, '8bit');
$ciphertext = mb_substr($message, 80, null, '8bit');
$calc = hash_hmac('sha512', $nonce.$ciphertext, $macKey, true);
if (!hash_equals($calc, $mac)) {
throw new Exception('Invalid MAC');
}
return openssl_decrypt(
$ciphertext,
'aes-256-ctr',
$encryptionKey,
OPENSSL_RAW_DATA,
$nonce
);
}
}
Usage
First, generate two keys (yes, two of them) and store them somehow.
$eKey = random_bytes(32);
$aKey = random_bytes(32);
Then to encrypt/decrypt messages:
$plaintext = 'This is just a test message.';
$encrypted = ExperimentalAES256DoNotActuallyUse::encrypt($plaintext, $eKey, $aKey);
$decrypted = ExperimentalAES256DoNotActuallyUse::decrypt($encrypted, $eKey, $aKey);
If you don't have random_bytes()
, get random_compat.

- 33,610
- 16
- 89
- 206
-
4Can you explain why it would not be a good idea to use the quick-and-dirty implementation in production if it does what is needed? – Nathan F. Sep 24 '16 at 01:29
-
You'll find that you want [defuse/php-encryption](https://github.com/defuse/php-encryption) rather than rolling your own or copying and pasting from StackOverflow. The only reason to roll your own is to create toy implementations to teach yourself. – Scott Arciszewski Sep 24 '16 at 02:29
-
2Yes, but say for example I wanted to handle something like stream ciphering from CPP over a socket to PHP. I've not personally looked into defuse's library, but is there a reason the generic AES256 written above wouldn't be suitable? Clearly not the exact code, but something similar as far as building the cipher. – Nathan F. Sep 27 '16 at 04:08
-
is this answer still up to date? (Just checking). I do not know the history of halite, but it seems to me that there is currently stable version of `v3.2.0` that's available – Dennis Jul 06 '17 at 18:48
-
Nothing has changed, except libsodium is due to land in PHP 7.2. – Scott Arciszewski Jul 07 '17 at 15:02
-
-
@ScottArciszewski, The other reason would be "not renting whole building just to store a piece of paper". – AaA Dec 19 '19 at 03:10
MCRYPT_RIJNDAEL_256 is not equivalent to AES_256.
The way to make RIJNDAEL be decrypted from AES is to use MCRYPT_RIJNDAEL_128 and padd the string to encrypt before encrypting
AES-256 has BlockSize=128bit and KeySize=256bit Rijndael-256 has BlockSize=256bit and KeySize=256bit
Just AES/Rijndael 128bit are identical. Rijndael-192 and Rijndael-256 are not identical to AES-192 and AES-256 (block sizes and number of rounds differ).

- 952
- 10
- 12
-
3You're certainly correct, but this post doesn't really answer the question. – CodesInChaos Jun 22 '13 at 13:18
-
Thanks @CodesInChaos. The way to make RIJNDAEL be decrypted from AES with openssl is to use MCRYPT_RIJNDAEL_128 and padd the string to encrypt before encrypting with the follwing function: – Behzad-Ravanbakhsh Jun 25 '13 at 09:53
You can encrypt & decrypt data using password_hash
function in PHP. You'll need a cost function too. Ensure you have OpenSSL and Mcrypt extensions enabled in your PHP environment.
<?php
$plaintext = 'My secret message 1234';
$password = '3sc3RLrpd17';
$method = 'aes-256-cbc';
$key = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// IV must be exact 16 chars (128 bit)
$iv = random_bytes(16);
$encrypted = base64_encode(openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv));
$decrypted = openssl_decrypt(base64_decode($encrypted), $method, $key, OPENSSL_RAW_DATA, $iv);
echo 'plaintext=' . $plaintext . "\n";
echo 'cipher=' . $method . "\n";
echo 'encrypted to: ' . $encrypted . "\n";
echo 'decrypted to: ' . $decrypted . "\n\n";
?>
$plaintext
: This variable holds the message we want to encrypt. In this example, “My secret message 1234” is the plaintext.$password
: Here, we define the password used to derive the encryption key.$method
: We set the encryption method to “aes-256-CBC,” which is the AES-256 encryption mode in Cipher Block Chaining (CBC) mode.$key
: The code generates the encryption key using the password provided, utilizing the password_hash() function with the PASSWORD_BCRYPT algorithm and a cost factor of 12.$iv
: The Initialization Vector (IV) is required for AES-256 in CBC mode and must be exactly 16 bytes long (128 bits).$encrypted
: The encrypted ciphertext is obtained by using the openssl_encrypt() function, which takes the plaintext, encryption method, encryption key, IV, and other parameters. The ciphertext is then Base64 encoded for easy representation.$decrypted
: To ensure the decryption process works, we use the openssl_decrypt() function to reverse the encryption process. This returns the original plaintext after decoding the Base64 representation.

- 1
- 2
-
1**Security warning**: Please do NOT use a **static** initialization vector as this makes the complete encryption vulnerable. Better use a random IV instead an prepend the IV to the encrypted password. – Michael Fehr Aug 01 '23 at 06:22
-
@MichaelFehr Thank you, It was for simplicity of code. I've changed the answer as per your suggestion. – Mostafa Safarian Aug 01 '23 at 06:45
-
Looks much better but, as a suggestion, print out the random IV (in Base64 encoding as well) so that a later decryption is possible (your code will work because the decryption is immediately followed by the decryption, but when e.g. storing just the ciphertext together with the passphrase you can't get the correct [first 16 bytes] of plaintext on decryption), thanks. – Michael Fehr Aug 01 '23 at 11:01
-
Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 04 '23 at 13:42
$key = '324325923495kdfgiert734t'; // key used for decryption in jasper code
$text = 'string_to_be_encrypted';
$encrypted = fnEncrypt($text, $key);
function fnEncrypt( $plaintext, $key )
{
$plaintext = pkcs5_pad($plaintext, 16);
return bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, hex2bin($key), $plaintext, MCRYPT_MODE_ECB));
}
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
function hex2bin($hexdata)
{
$bindata = "";
for ($i = 0; $i < strlen($hexdata); $i += 2)
{
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}

- 77
- 1
- 4
-
Please explain your answer in brief to make it more useful for OP and other readers. – Mohit Jain May 27 '14 at 08:46
-
1