I have a need to encrypt cookies on my site. Lets assume that the data that I wanted to encrypt is my session ID for simplicity.
Here is how I would generate my cookie and encrypt it using PHP openSSL, and decrypt it.
/**
* Encrypt any cookie
* #param $content
* #param $key_name
* #param $iv_name
* #return string
*/
function encrypt_cookie(string $content, string $key_name, string $iv_name): string
{
$method = 'AES-256-CFB';
$ivLength = openssl_cipher_iv_length($method);
$needStrong = true;
$keyLength = 256;
if (!isset($_SESSION[$key_name])) {
$key = openssl_random_pseudo_bytes($keyLength, $needStrong);
$_SESSION[$key_name] = $key;
} else {
$key = $_SESSION[$key_name];
}
$iv = openssl_random_pseudo_bytes($ivLength, $needStrong);
$_SESSION[$iv_name] = $iv;
return openssl_encrypt($content, $method, $key, $options=OPENSSL_RAW_DATA, $iv);
}
/**
* Decrypt any cookie
* #param string $cookie_name
* #param string $key_name
* #param $iv_name
* #return string
*/
function decrypt_cookie(string $cookie_name, string $key_name, $iv_name): string
{
$data = $_COOKIE[$cookie_name];
$method = 'AES-256-CFB';
$key = $_SESSION[$key_name];
$options = OPENSSL_RAW_DATA;
$iv = $_SESSION[$iv_name];
return openssl_decrypt($data, $method, $key, $options, $iv);
}
/**
* Create the cookie and set its value to an
* encrypted version of my session ID
*/
function cooking_snickerdoodles(): void
{
$cookie_name = "sugar_cookie";
$content = session_id();
$key_name = 'timeout_cookie_key';
$iv_name = 'sugar_cookie_iv';
$hex = encrypt_cookie($content, $key_name, $iv_name);
setcookie($cookie_name, $hex);
}
The encryption works great. It outputs something and I can read it if I convert it using bin2hex(). However my decryption method isn't working at all. I checked in my browser developer tools and 'sugar_cookie' is shown as one of the cookies.
When I try to echo out the result of decrypt_cookie() I am getting absolutely nothing, even if I pass it into bin2hex.
This next code isn't really important but it is what I am using to make sure that the session data matches the cookie data:
function has_the_cookie($cookie_name): bool
{
if (isset($_COOKIE[$cookie_name])) {
return true;
} else {
return false;
}
}
function cookie_tastes_right(): bool
{
$crumbs = $_COOKIE['sugar_cookie'];
$whole_cookie = decrypt_cookie($crumbs, $_SESSION['timeout_cookie_key'], $_SESSION['sugar_cookie_iv']);
if ($whole_cookie === session_id()) {
return true;
} else {
return false;
}
}
function confirm_cookie_in_bag(): void
{
if (!has_the_cookie('sugar_cookie') || !cookie_tastes_right()) {
end_session();
redirect_to(url_for('admin/login.php'));
}
}
EDIT - SHOWING UPDATED FUNCTIONS that don't store binary
/**
* Encrypt any cookie
* #param $content
* #param $key_name
* #param $iv_name
* #return string
*/
function encrypt_cookie(string $content, string $key_name, string $iv_name): string
{
$method = 'AES-256-CFB';
$ivLength = openssl_cipher_iv_length($method);
$needStrong = true;
$keyLength = 256;
if (!isset($_SESSION[$key_name])) {
$key = openssl_random_pseudo_bytes($keyLength, $needStrong);
$_SESSION[$key_name] = $key;
} else {
$key = $_SESSION[$key_name];
}
$iv = openssl_random_pseudo_bytes($ivLength, $needStrong);
$_SESSION[$iv_name] = $iv;
return bin2hex(openssl_encrypt($content, $method, $key, $options=OPENSSL_RAW_DATA, $iv));
}
/**
* Decrypt any cookie
* #param string $cookie_name
* #param string $key_name
* #param $iv_name
* #return string
*/
function decrypt_cookie(string $cookie_name, string $key_name, $iv_name): string
{
$data = hex2bin($_COOKIE[$cookie_name]);
$method = 'AES-256-CFB';
$key = $_SESSION[$key_name];
$options = OPENSSL_RAW_DATA;
$iv = $_SESSION[$iv_name];
//ECHO and exit for demo purposes only
echo bin2hex(openssl_decrypt($data, $method, $key, $options, $iv));
exit;
}
You're using OPENSSL_RAW_DATA - the output from this call won't be hex, it will be binary. Storing raw binary in a cookie is a no-go! You'd probably prefer base64 over hex, which is the default behaviour.
Related
I am trying to get a php equivalent of this node function to be able to encrypt some data in php before decrypting it in node
/**
* Encrypts an object with aes-256-cbc to use as a token
* #param {any} data An object to encrypt
* #param {string} secret The secret to encrypt the data with
* #returns {string}
*/
static encrypt(data, secret) {
const iv = randomBytes(16);
const cipher = createCipheriv('aes-256-cbc', secret, iv);
return `${cipher.update(JSON.stringify(data), 'utf8', 'base64') + cipher.final('base64')}.${iv.toString('base64')}`;
}
This is the php function I have come up with, along with the necessary helper functions
/**
* Encrypts an object with aes-256-cbc to use as a token
* #param $data An object to encrypt
* #param $secret The secret to encrypt data with
* #return \Illuminate\Http\Response
*/
public function encrypt($data, $secret)
{
$method = 'AES-256-CBC';
$data = static::getPaddedText($data);
$iv = static::generateIv();
$ciphertext = openssl_encrypt(json_encode($data), $method, $secret, OPENSSL_RAW_DATA, $iv);
$ciphertext_64 = base64_encode(utf8_encode($ciphertext));
$iv_64 = base64_encode($iv);
return "$ciphertext_64.$iv_64";
}
private static function getPaddedText(string $plainText): string
{
$blocksize = 8;
$textLength = strlen($plainText);
if ($textLength % $blocksize) {
$plainText = str_pad($plainText, $textLength + $blocksize - $textLength % $blocksize, "\0");
}
return $plainText;
}
public static function generateIv(): string
{
$ivLength = 16;
$success = false;
$random = openssl_random_pseudo_bytes($ivLength, $success);
if (!$success) {
$random = random_bytes($ivLength);
}
return $random;
}
But I dont think it is exactly the same as when decrypting it with this function
/**
* Decrypts an object with aes-256-cbc to use as a token
* #param {string} token An data to decrypt
* #param {string} secret The secret to decrypt the data with
* #returns {any}
*/
static decrypt(token, secret) {
const [data, iv] = token.split('.');
const decipher = createDecipheriv('aes-256-cbc', secret, Buffer.from(iv, 'base64'));
return JSON.parse(decipher.update(data, 'base64', 'utf8') + decipher.final('utf8'));
}
I get this error EVP_DecryptFinal_ex:wrong final block length
Looks like you aren't padding your text with nulls to ensure you have block sizes that are exactly eight characters long. In pother words, your string needs to be a multiple of eight in length. Padding your string with nulls will accomplish that for you without changing its value.
class AES256Encryption
{
public const BLOCK_SIZE = 8;
public const IV_LENGTH = 16;
public const CIPHER = 'AES-256-CBC';
public static function generateIv(): string
{
$success = false;
$random = openssl_random_pseudo_bytes(static::IV_LENGTH, $success);
if (!$success) {
$random = random_bytes(static::IV_LENGTH);
}
return $random;
}
private static function getPaddedText(string $plainText): string
{
$textLength = strlen($plainText);
if ($textLength % static::BLOCK_SIZE) {
$plainText = str_pad($plainText, $textLength + static::BLOCK_SIZE - $textLength % static::BLOCK_SIZE, "\0");
}
return $plainText;
}
public static function encrypt(string $plainText, string $key, string $iv): string
{
$plainText = static::getPaddedText($plainText);
return base64_encode(openssl_encrypt($plainText, static::CIPHER, $key, OPENSSL_RAW_DATA, $iv));
}
public static function decrypt(string $encryptedText, string $key, string $iv): string
{
return openssl_decrypt(base64_decode($encryptedText), static::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
}
}
Usage:
$key = 'secretkey';
$iv = AES256Encryption::generateIv();
$text = 'The quick brown fox jumps over the lazy dog';
$encryptedText = AES256Encryption::encrypt($text, $key, $iv);
$decryptedText = AES256Encryption::decrypt($encryptedText, $key, $iv);
printf('Original Text: %s%s', $text, PHP_EOL);
printf('Encrypted : %s%s', $encryptedText, PHP_EOL);
printf('Decrypted : %s%s', $decryptedText, PHP_EOL);
Output:
Original Text: The quick brown fox jumps over the lazy dog
Encrypted : 1J+0tGHzn67WA7kJGjp9malmv0w+tcl0t8YnC+F9Y9IZWMDeBH4+k9TyuznF77cWe1SGUWa6Pb6r/i0xmH+ajg==
Decrypted : The quick brown fox jumps over the lazy dog
Your usage:
// Your encoding usage:
$key = 'secret';
$iv = AES256Encryption::generateIv();
$text = 'The quick brown fox jumps over the lazy dog';
$encryptedText = AES256Encryption::encrypt($text, $key, $iv);
$finalString = $encryptedText . bin2hex($iv);
// Your decoding usage:
$iv = hex2bin(substr($finalString, -32, 32));
$decryptedText = AES256Encryption::decrypt($encryptedText, $key, $iv);
printf('Original Text : %s%s', $text, PHP_EOL);
printf('Encrypted : %s%s', $encryptedText, PHP_EOL);
printf('Encrypted w/Iv: %s%s', $finalString, PHP_EOL);
printf('Decrypted : %s%s', $decryptedText, PHP_EOL);
Output:
Original Text : The quick brown fox jumps over the lazy dog
Encrypted : +JsjXFPdyTycYrc2fOb1edLKNksEUHzEGxwRewBlA8yxBWZZV2y/EVIwk0g9g17dtxAaTGZvYaf2y9+oTCvLWg==
Encrypted w/Iv: +JsjXFPdyTycYrc2fOb1edLKNksEUHzEGxwRewBlA8yxBWZZV2y/EVIwk0g9g17dtxAaTGZvYaf2y9+oTCvLWg==54993615360ff641a952a553e1500568
Decrypted : The quick brown fox jumps over the lazy dog
Generating the IV can be more robust as random_bytes() can throw an exception.
This is my code :
function verifyRequest($request, $secret) {
// Per the Shopify docs:
// Everything except hmac and signature...
$hmac = $request['hmac'];
unset($request['hmac']);
unset($request['signature']);
// Sorted lexilogically...
ksort($request);
// Special characters replaced...
foreach ($request as $k => $val) {
$k = str_replace('%', '%25', $k);
$k = str_replace('&', '%26', $k);
$k = str_replace('=', '%3D', $k);
$val = str_replace('%', '%25', $val);
$val = str_replace('&', '%26', $val);
$params[$k] = $val;
}
echo $http = "protocol=". urldecode("https://").http_build_query( $params) ;
echo $test = hash_hmac("sha256", $http , $secret);
// enter code hereVerified when equal
return $hmac === $test;
}
The hmac from shopi and hmac created from my code is not matching.
What am I doing wrong?
You only need to include the request parameters when creating the list of key-value pairs - don't need "protocol=https://".
https://help.shopify.com/api/getting-started/authentication/oauth#verification
You'll need to urldecode() the result of http_build_query(). It returns a url-encoded query string.
http://php.net/manual/en/function.http-build-query.php
Instead of:
echo $http = "protocol=". urldecode("https://").http_build_query( $params) ;
echo $test = hash_hmac("sha256", $http , $secret);
Something like this:
$http = urldecode(http_build_query($params));
$test = hash_hmac('sha256', $http, $secret);
hmac can be calculated in any programming language using sha256 cryptographic algorithm.
However the doc for hmac verification is provided by shopify but still there is confusion among app developers how to implement it correctly.
Here is the code in php for hmac verification.
Ref. http://code.codify.club
<?php
function verifyHmac()
{
$ar= [];
$hmac = $_GET['hmac'];
unset($_GET['hmac']);
foreach($_GET as $key=>$value){
$key=str_replace("%","%25",$key);
$key=str_replace("&","%26",$key);
$key=str_replace("=","%3D",$key);
$value=str_replace("%","%25",$value);
$value=str_replace("&","%26",$value);
$ar[] = $key."=".$value;
}
$str = join('&',$ar);
$ver_hmac = hash_hmac('sha256',$str,"YOUR-APP-SECRET-KEY",false);
if($ver_hmac==$hmac)
{
echo 'hmac verified';
}
}
?>
Notice for other requests like the App Proxy a HMAC will not be preset, so you'll need to calculate the signature. Here a function that caters for both types of requests including webhooks:
public function authorize(Request $request)
{
if( isset($request['hmac']) || isset($request['signature']) ){
try {
$signature = $request->except(['hmac', 'signature']);
ksort($signature);
foreach ($signature as $k => $val) {
$k = str_replace('%', '%25', $k);
$k = str_replace('&', '%26', $k);
$k = str_replace('=', '%3D', $k);
$val = str_replace('%', '%25', $val);
$val = str_replace('&', '%26', $val);
$signature[$k] = $val;
}
if(isset($request['hmac'])){
$test = hash_hmac('sha256', http_build_query($signature), env('SHOPIFY_API_SECRET'));
if($request->input('hmac') === $test){
return true;
}
} elseif(isset($request['signature'])){
$test = hash_hmac('sha256', str_replace('&', '', urldecode(http_build_query($signature))), env('SHOPIFY_API_SECRET'));
if($request->input('signature') === $test){
return true;
}
}
} catch (Exception $e) {
Bugsnag::notifyException($e);
}
} else { // If webhook
$calculated_hmac = base64_encode(hash_hmac('sha256', $request->getContent(), env('SHOPIFY_API_SECRET'), true));
return hash_equals($request->server('HTTP_X_SHOPIFY_HMAC_SHA256'), $calculated_hmac);
}
return false;
}
The above example uses some Laravel functions, so уоu may want to replace them if you use a different framework.
I've got the following to do this:
// Remove the 'hmac' parameter from the query string
$query_string_rebuilt = removeParamFromQueryString($_SERVER['QUERY_STRING'], 'hmac');
// Check the HMAC
if(!checkHMAC($_GET['hmac'], $query_string_rebuilt, $shopify_api_secret_key)) {
// Error code here
}
/**
* #param string $comparison_data
* #param string $data
* #param string $key
* #param string $algorithm
* #param bool $binary
* #return bool
*/
function checkHMAC($comparison_data, $data, $key, $algorithm = 'sha256', $binary=false) {
// Check the HMAC
$hash_hmac = hash_hmac($algorithm, $data, $key, $binary);
// Return true if there's a match
if($hash_hmac === $comparison_data) {
return true;
}
return false;
}
/**
* #param string $query_string
* #param string $param_to_remove
* #return string
*/
function removeParamFromQueryString(string $query_string, string $param_to_remove) {
parse_str($query_string, $query_string_into_array);
unset($query_string_into_array[$param_to_remove]);
return http_build_query($query_string_into_array);
}
I have index ponter, for example 5-1-key2-3.
And my array has its address:
array(
'5'=>array(
'1'=>array(
'key2'=>array(
'3'=>'here it is - 5-1-key2-3 key address'
)
)
)
)
which equals to
$arr[5][1][key2][3]='here it is - 5-1-key2-3 key address';
I know I can build the recursive function to access this value.
But I'm curious is it possible to achieve this without recursion and building user's functions and/or loops.
Probably it can be done with variable variables feature in php.
You can use this code
$keys = explode('-', '5-1-key2-3');
// start from the root of the array and progress through the elements
$temp = $arr;
foreach ($keys as $key_value)
{
$temp = $temp[$key_value];
}
// this will give you $arr["5"]["1"]["key2"]["3"] element value
echo $temp;
modifications after I got better understanding of the question I think you can do it with eval:
<?php
function getArrValuesFromString($string, $arr) {
$stringArr = '$arr[\'' . str_replace('-', "']['", $string) . '\']';
eval("\$t = " . $stringArr . ";");
return $t;
}
$arr[5][1]['key2'][3] = '1here it is - 5-1-key2-3 key address';
$string = '5-1-key2-3';
echo getArrValuesFromString($string, $arr); //1here it is - 5-1-key2-3 key address
EDIT :
Here is a way I deprecate so much, because of security, but if you are sure of what you are doing :
$key = 'a-b-c-d';
$array = <<your array>>;
$keys = explode('-', $key);
// we can surely do something better like checking for each one if its a string or int then adding or not the `'`
$final_key = "['".implode("']['", $keys)."']";
$result = eval("return \$array{$final_key};");
There is a class I wrote inspired from something I read on the web don't really remember where but anyway, this can helps you :
/**
* Class MultidimensionalHelper
*
* Some help about multidimensional arrays
* like dynamic array_key_exists, set, and get functions
*
* #package Core\Utils\Arrays
*/
class MultidimensionalHelper
{
protected $keySeparator = '.';
/**
* #return string
*/
public function keySeparator()
{
return $this->keySeparator;
}
/**
* #param string $keySeparator
*/
public function setKeySeparator($keySeparator)
{
$this->keySeparator = $keySeparator;
}
/**
* Multidimensional array dynamic array_key_exists
*
* #param $key String Needle
* #param $array Array Haystack
* #return bool True if found, false either
*/
public function exists($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$tmp = $array;
foreach($keys as $k)
{
if(!array_key_exists($k, $tmp))
{
return false;
}
$tmp = $tmp[$k];
}
return true;
}
/**
* Multidimensional array dynamic getter
*
*
* #param $key String Needle
* #param $array Array Haystack
* #return mixed Null if key not exists or the content of the key
*/
public function get($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = $array;
foreach($keys as $k)
{
if(!isset($tmp[$k]))
{
return null;
}
$tmp = $tmp[$k];
}
return $tmp[$lkey];
}
/**
* Multidimensional array dynamic setter
*
* #param String $key
* #param Mixed $value
* #param Array $array Array to modify
* #param Bool $return
* #return Array If $return is set to TRUE (bool), this function
* returns the modified array instead of directly modifying it.
*/
public function set($key, $value, &$array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = &$array;
foreach($keys as $k)
{
if(!isset($tmp[$k]) || !is_array($tmp[$k]))
{
$tmp[$k] = array();
}
$tmp = &$tmp[$k];
}
$tmp[$lkey] = $value;
unset($tmp);
}
}
Then use :
$MDH = new MultidimensionalHelper();
$MDH->setKeySeparator('-');
$arr = [
'a' => [
'b' => [
'c' => 'good value',
],
'c' => 'wrong value',
],
'b' => [
'c' => 'wrong value',
]
];
$key = 'a-b-c';
$val = $MDH->get($key, $arr);
var_dump($val);
Here is the content of the get function if you don't find it in Class code :
public function get($key, $array)
{
$keys = explode($this->keySeparator(), $key);
$lkey = array_pop($keys);
$tmp = $array;
foreach($keys as $k)
{
if(!isset($tmp[$k]))
{
return null;
}
$tmp = $tmp[$k];
}
return $tmp[$lkey];
}
When I try to execute this file, it show me black page..
i start the firebug it shows me that NetworkError: 500 Internal Server Error
i tried to solve but cant find any problem here..
so could you help me to find what is the error or problem..??
class DesEncryptor
{
protected $_key;
protected $_iv;
protected $_blocksize = 8;
protected $_encrypt;
protected $_cipher;
/**
* Creates a symmetric Data Encryption Standard (DES) encryptor object
* with the specified key and initialization vector.
*
* #param $key
* #param $iv
* #param bool $encrypt
*/
public function __construct($key, $iv, $encrypt = true)
{
$this->_key = $key;
$this->_iv = $iv;
$this->_encrypt = $encrypt;
$this->_cipher = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($this->_cipher, $this->_key, $this->_iv);
}
public function __destruct()
{
mcrypt_generic_deinit($this->_cipher);
mcrypt_module_close($this->_cipher);
}
/**
* Transforms the specified region of the specified byte array using PCKS7 padding.
* #param $text
* #return string
*/
public function transformFinalBlock($text)
{
if ($this->_encrypt)
{
$padding = $this->_blocksize - strlen($text) % $this->_blocksize;
$text .= str_repeat(pack('C', $padding), $padding);
}
$text = $this->transformBlock($text);
if (!$this->_encrypt)
{
$padding = array_values(unpack('C', substr($text, -1)))[0];
$text = substr($text, 0, strlen($text) - $padding);
}
return $text;
}
/**
* Transforms the specified region of the specified byte array.
* #param $text
* #return string
*/
public function transformBlock($text)
{
if ($this->_encrypt)
{
return mcrypt_generic($this->_cipher, $text);
}
else
{
return mdecrypt_generic($this->_cipher, $text);
}
}
}
When i debug with var_dump(), i found that in function transformFinalBlock
$padding = array_values(unpack('C', substr($text, -1)))[0];
it throw me error like " '[' is unexpected "
Guys, solutions plz...
Array de-referencing, which is what you are doing with the line $padding = array_values(unpack('C', substr($text, -1)))[0];, is only possible as of php 5.4, any prior versions, you will have to do the following to access your array:
$arr = array_values(unpack('C', substr($text, -1)));
$padding = $arr[0];
There is a function in Mysql AES_encrypt.
SELECT AES_encrypt( "Hello World", "password" ) AS encrypted_value
This gives the result: 9438eb79863e7009722fc3f0ad4b7198
But when I use the code in php to do AES_encrypt it gives me a different value.
The PHP code I got from stackoverflow -- PHP AES encrypt / decrypt
<?php
base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$sSecretKey, $sValue,
MCRYPT_MODE_ECB,
mcrypt_create_iv(
mcrypt_get_iv_size(
MCRYPT_RIJNDAEL_256,
MCRYPT_MODE_ECB
),
MCRYPT_RAND)
)
), "\0"
?>
The result from PHP code is ytip2sEkD87gmRk3IVI09qE7T+RoLr20YK4rJp16NkY=
Is there a method in php or codeigniter so that it returns the same value.?
--Thank you.
There are three problems with the code you are using:
As others have mentioned, your PHP code is currently using MCRYPT_RIJNDAEL_256 whereas, as documented under AES_ENCRYPT():
Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source. We chose 128 bits because it is much faster and it is secure enough for most purposes.
As others have mentioned, you are applying base64_encode() to convert PHP's binary result to text, whereas the MySQL result appears merely to be a hexadecimal representation of its binary result. You can either use TO_BASE64() in MySQL since v5.6.1 or else bin2hex() in PHP.
As documented under mcrypt_encrypt():
If the size of the data is not n * blocksize, the data will be padded with '\0'.
Whereas MySQL uses PKCS7 padding.
Therefore, to obtain the same results in PHP as you currently show for MySQL:
<?php
class MySQL_Function {
const PKCS7 = 1;
private static function pad($string, $mode, $blocksize = 16) {
$len = $blocksize - (strlen($string) % $blocksize);
switch ($mode) {
case self::PKCS7:
$padding = str_repeat(chr($len), $len); break;
default:
throw new Exception();
}
return $string.$padding;
}
public static function AES_ENCRYPT($str, $key_str) {
return mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$key_str, self::pad($str, self::PKCS7),
MCRYPT_MODE_ECB
);
}
}
echo bin2hex(MySQL_Function::AES_encrypt( "Hello World", "password" ));
?>
mcrypt_encrypt is deprecated, so here's a solution that's capable of falling back on openssl_encrypt instead. Truthfully, I don't know how all of it works. It's kind of a composite of some solutions I found regarding replicating MySQL's AES_ENCRYPT in mcrypt_encrypt, and then replicating mcrypt_encrypt in openssl_encrypt. The generation of the key from what would otherwise be used as the salt arguments in AES_ENCRYPT, as well as understanding which cypher to use when, is a little beyond me. But I can say these functions have been time-tested to be functionally identical to their MySql counterparts.
if (!function_exists('mysql_aes_key')) {
/**
* #param string $key
* #return string
*/
function mysql_aes_key($key)
{
$new_key = str_repeat(chr(0), 16);
for ($i = 0, $len = strlen($key); $i < $len; $i++) {
$new_key[$i % 16] = $new_key[$i % 16] ^ $key[$i];
}
return $new_key;
}
}
if (!function_exists('aes_encrypt')) {
/**
* #param string $val
* #param string $cypher
* #param bool $mySqlKey
* #return string
* #throws \BadFunctionCallException
*/
function aes_encrypt($val, $cypher = null, $mySqlKey = true)
{
$salt = getenv('SALT') ?: '1234567890abcdefg';
$key = $mySqlKey ? mysql_aes_key($salt) : $salt;
if (function_exists('mcrypt_encrypt')) {
$cypher = (!$cypher || $cypher == strtolower('aes-128-ecb')) ? MCRYPT_RIJNDAEL_128 : $cypher;
$pad_value = 16 - (strlen($val) % 16);
$val = str_pad($val, (16 * (floor(strlen($val) / 16) + 1)), chr($pad_value));
return #mcrypt_encrypt($cypher, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));
} elseif (function_exists('openssl_encrypt')) {
//TODO: Create a more comprehensive map of mcrypt <-> openssl cyphers
$cypher = (!$cypher || $cypher == MCRYPT_RIJNDAEL_128) ? 'aes-128-ecb' : $cypher;
return openssl_encrypt($val, $cypher, $key, true);
}
throw new \BadFunctionCallException('No encryption function could be found.');
}
}
if (!function_exists('aes_decrypt')) {
/**
* #param string $val
* #param string $cypher
* #param bool $mySqlKey
* #return string
* #throws \BadFunctionCallException
*/
function aes_decrypt($val, $cypher = null, $mySqlKey = true)
{
$salt = getenv('SALT') ?: '1234567890abcdefg';
$key = $mySqlKey ? mysql_aes_key($salt) : $salt;
if (function_exists('mcrypt_decrypt')) {
$cypher = (!$cypher || $cypher == strtolower('aes-128-ecb')) ? MCRYPT_RIJNDAEL_128 : $cypher;
$val = #mcrypt_decrypt($cypher, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));
return rtrim($val, chr(0)."..".chr(16));
} elseif (function_exists('openssl_decrypt')) {
//TODO: Create a more comprehensive map of mcrypt <-> openssl cyphers
$cypher = (!$cypher || $cypher == MCRYPT_RIJNDAEL_128) ? 'aes-128-ecb' : $cypher;
return openssl_decrypt($val, $cypher, $key, true);
}
throw new \BadFunctionCallException('No decryption function could be found.');
}
}
So...
putenv('SALT=1234567890abcdefg');
aes_encrypt('some_value') === SELECT AES_ENCRYPT('some_value', '1234567890abcdefg')
aes_decrypt('some_encrypted_value') === SELECT AES_DECRYPT('some_encrypted_value', '1234567890abcdefg')
I tested these by encrypting a value with the php function, and decrypting it with the MySQL one, and visa-versa.
The MySQL AES_encrypt uses a 128-bit key length - Reference here
Whereas your PHP code uses 256-bit key lengths.
To fix the problem you should be able to uses 'MCRYPT_RIJNDAEL_128' instead of 256.
The accepted answer works but is a lot of code, Here's the one liner
function aes_encrypt_str($val,$key){
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key, $val,MCRYPT_MODE_ECB,mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,MCRYPT_MODE_ECB),MCRYPT_RAND));
}