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?
-
Here is a good blog post explaining how to work with MCrypt library: code-epicenter.com/how-to-use-mcrypt-library-in-php– MrDCommented Apr 9, 2016 at 22:06
4 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
-
15-1, AES-256 is different from
RIJNDAEL-256
. The 256 inAES
refers to the key size, where the 256 inRIJNDAEL
refers to block size.AES-256
isRIJNDAEL-128
when used with a 256 bit key. Commented Jun 22, 2013 at 11:50 -
3@CodesInChaos I've edited the answer according to your observations. Now the answer should be correct.– FabioCommented Jun 22, 2013 at 16:00
-
3I just want to emphasize that MACs are really important if active attacks are possible. A well known attack is the "padding oracle" where the reaction of the recipient leaks information about the plaintext allowing byte-by-byte recovery of the plaintext by querying the recipient. Commented Jun 22, 2013 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)– DEzraCommented Mar 18, 2015 at 12:59
-
3PHP has deprecated
mcrypt
library, it will be removed from PHP version after 7.1. As such, using suggesting mcrypt makes this answer deprecated. See php.net/manual/en/migration71.deprecated.php– DennisCommented Jul 6, 2017 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.
-
5Can 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? Commented Sep 24, 2016 at 1:29
-
You'll find that you want 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. Commented Sep 24, 2016 at 2: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. Commented Sep 27, 2016 at 4: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– DennisCommented Jul 6, 2017 at 18:48 -
1@ScottArciszewski, The other reason would be "not renting whole building just to store a piece of paper".– AaACommented Dec 19, 2019 at 3: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).
-
3You're certainly correct, but this post doesn't really answer the question. Commented Jun 22, 2013 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: <?php function pkcs5_pad ($text, $blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad), $pad); } ?> Commented Jun 25, 2013 at 9:53
$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;
}
-
Please explain your answer in brief to make it more useful for OP and other readers. Commented May 27, 2014 at 8:46
-
1Kindly add the decrypt function also.– user216084Commented Dec 24, 2014 at 11:42