AES_DECRYPT Paired With openssl_encrypt - php

I have a php program that stores encrpyted data in the database using openssl_encrypt.
I need to be able to decrypt this data in mysql to perform queries on it.
The problem is that im not sure what the value of my key should be in the AES_DECRYPT function of mysql.
My php code uses a base64 key that decrypts to a non ascii value.
The code base64 encodes the encrypted value and adds the IV at the end, so in mysql i decode and split this. All of that is working fine, but when i go to decrypt it returns null. presumably because i dont know how to put the key in correctly.
Ive tried UNHEX("key") FROM_BASE64("key") etc
function encrypt($data)
{
if (!$data) {
return null;
}
$key = "lvvs9pxoekc54zsBpsp+/H1235BdjsAscdRRAxr47uw="; //this is not my real key
$encryption_key = base64_decode($key);
$hex = bin2hex($encryption_key);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}
In mysql i am doing this
AES_DECRYPT(
FROM_BASE64(SUBSTRING_INDEX(
UPPER(
CAST(
FROM_BASE64(member_ssn)
AS CHAR(1000)
)
), '::', 1))
, '*KEY* what do i need to put here?') as decrpyted_string

I got this working so i will post my solution for those who care.
The code performs the following opperations.
takes a base64 value and decodes it
this results in a value of base64cryptstring::IV
then splits the string at the :: to get the IV and crypt string separated
then it uses these values and a FROM_BASE64 on the key itself to get the decrpyted value
SELECT dec_data.member_id, CONVERT(dec_data.dec_ssn USING LATIN1) as dec_ssn FROM (
select
*,
CAST(
AES_DECRYPT(
FROM_BASE64(SUBSTRING_INDEX(CAST(FROM_BASE64(member_ssn)AS CHAR(1000)), '::', 1)),
FROM_BASE64('yourbase64keyhere=='),
SUBSTRING_INDEX(SUBSTRING_INDEX(FROM_BASE64(member_ssn), '::', 2), '::', -1)
) AS CHAR) as dec_ssn
from lb_1_members where member_ssn is not null AND member_ssn != '') dec_data

Related

PHP "randomize" the rand() function?

Hi everyone I was wondering what could be possible to randomize this code even further :
<?php
$key=md5('ILOVEYOU');
$serverseed = floor(time() / 5);
srand($serverseed);
$result = rand();
$modulus_result= $result % 100;
echo "before: ".$modulus_result."<br>";
echo "after: ".encrypt($modulus_result, $key)."<br>";
echo decrypt($modulus_result, $key);
function decrypt($string, $key){
$string = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($string), MCRYPT_MODE_ECB));
return $string;
}
function encrypt($string, $key){
$string = rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_ECB)));
return $string;
}
?>
Ok for everyone that stumbled upon this thread and missunderstood the topic, I'm not using this function to protect ANYTHING inside my website, I'm just looking ways to randomize this function as it uses time() as a reference...
I need to generate a random int from 1-100, that seems to work, I'm just looking for other ways to randomize it( if I could explain a bit more, adding some sort of "salt" not encryption of any sort.)
Check the documentation:
This function does not generate cryptographically secure values, and
should not be used for cryptographic purposes. If you need a
cryptographically secure value, consider using random_int(),
random_bytes(), or openssl_random_pseudo_bytes() instead.
You might want to use random_int instead.
The problem with that is that was introduced with PHP 7 so you might not be able to use it. In this case, you can get it here, as mentioned in the documentation.

How to calculate proper KCV value for a 3des encryption Key?

I'm trying to calculate KCV for a DES encryption.
$data = 'F337CE3C64E02D96C61A9EC69E051D5A';
$transport = '4B4D3733504D3735';
$encData = bin2hex(mcrypt_encrypt(MCRYPT_DES, pack('H*', $transport),
$data, MCRYPT_MODE_ECB));
This is all fine, data gets properly encrypted.
Now I want to calculate KCV.
$key = 'F337CE3C64E02D96C61A9EC69E051D5A';
$zeroBytes = 00000000;
$kcv = bin2hex(mcrypt_encrypt(MCRYPT_3DES, $key, $zeroBytes, MCRYPT_MODE_ECB));
var_dump($kcv);
this returns wrong value : 953f34d098f996f9 and it should be (the final kcv) 53173F. What goes wrong here?
I see two issues with your code: 1. Key should be binary, 2. Null bytes should be used, not integer zeros.
$key = pack('H*', '0123456789ABCDEF');
$data = "\0\0\0\0\0\0\0\0";
$kcv = strtoupper(bin2hex(mcrypt_encrypt(MCRYPT_3DES, $key, $data, MCRYPT_MODE_ECB)));
var_dump($kcv);
This outputs D5D44FF720683D0D as expected (KCV for key 0123456789ABCDEF is D5D44FF720683D0D).
EDIT: In your case you need to append the first 16 characters to the end of the key to get the correct KCV:
$key = 'F337CE3C64E02D96C61A9EC69E051D5A';
$key .= substr($key, 0, 16);
$key = pack('H*', $key);
$data = "\0\0\0\0\0\0\0\0";
$kcv = strtoupper(bin2hex(mcrypt_encrypt(MCRYPT_3DES, $key, $data, MCRYPT_MODE_ECB)));
var_dump($kcv);
This outputs 53173F8B139F34FE. See Keying options for more details:
The standards define three keying options:
Keying option 1: All three keys are independent.
Keying option 2: K1 and K2 are independent, and K3 = K1.
Keying option 3: All three keys are identical, i.e. K1 = K2 = K3.
I'm no cryptographer, but a quick googling says that a 3DES KCV needs to be calculated on a "string of binary zeroes", and $zeroBytes = 00000000; is not that.
PHP will read that as 0, then type-juggle that into an ASCII zero character, aka 0x30.
I think what you want is:
$zeroBytes = "\0\0\0\0\0\0\0\0";
Which will give you eight NULL bytes, aka 0x00.

How to create a signature for Instamojo's payment link in PHP?

I would like to know which function I can use to create signature for Instamojo's payment links in PHP and what procedure should I follow if I had an array of read-only values?
You can use the hash_hmac function in PHP to create the signature. Instamojo uses "sha1" algorithm, so, your hash_hmac call will looks like:
hash_hmac("sha1", $message, $salt)
Here $message is going to be the "|" separated values and $salt will be private salt from the developers page(make sure you are logged in).
The algorithm for generating $message is:
Arrange the read-only fields in the alphabetical order of their keys. If you have any keys with upper-case letters, convert them to lower-case letters first.
Let's say the url is:
https://www.instamojo.com/demo/demo-offer/?data_name=Aditya+Sengupta&data_email=aditya#instamojo.com&data_phone=9999999999&data_amount=123.45&data_readonly=data_name&data_readonly=data_email&data_readonly=data_phone&data_readonly=data_amount
For the above url you would get the following order:
data_amount
data_email
data_name
data_phone
Using the above order of keys we will get the values in following order:
123.45
aditya#instamojo.com
Aditya Sengupta
9999999999
Now concatenate the above values using |(pipe) operator, so $message will look like:
123.45|aditya#instamojo.com|Aditya Sengupta|9999999999
If your $salt is "abcde" then you will get this as signature:
$ php -a
Interactive shell
php > $message = "123.45|aditya#instamojo.com|Aditya Sengupta|9999999999";
php > $salt = "abcde";
php > echo hash_hmac("sha1", $message, $salt) . "\n";
676a4b5ba30e464f027249747a63ea587f8c4b9a
How to do this if I had an array of read-only values?
Well you need to sort the array by keys first, it should be case-insensive. If you're using PHP 5.4.0 + you can do something like this:
php > $read_only_fields = ["data_email" => "aditya#instamojo.com", "data_Phone" => "9999999999", "data_name" => "Aditya Sengupta", "data_Amount" => "123.45"];
php > ksort($read_only_fields, SORT_STRING | SORT_FLAG_CASE);
php > $message = implode('|', $read_only_fields);
php > echo $message . "\n";
123.45|aditya#instamojo.com|Aditya Sengupta|9999999999
php > $salt = "abcde";
php > echo hash_hmac("sha1", $message, $salt) . "\n";
676a4b5ba30e464f027249747a63ea587f8c4b9a
For older versions of PHP(older than 5.4.0) use this for sorting:
uksort($data, 'strcasecmp');
For more info read their Integration documentation and How do I ensure that the link is tamper proof?.

Decrypt CryptoJS in PHP - where does the IV go

I am using this function to supply a custom key for encrypting a string using CryptoJS
function doHash(msg){
msg = String(msg);
var key = CryptoJS.enc.Hex.parse('000102030405060708090a0b0c0d0e0f');
var iv = CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');
var encrypted = CryptoJS.AES.encrypt(msg, key, { iv: iv });
return encrypted;
}
Instead of supplying a passphrase I directly supply an IV and a key to encrypt.
Now I need to decrypt the ciphertext in PHP:
And this is what I found:
function aes_decrypt($encrypted,$key)
{
// if $encrypted is HEXed, then return it to binary
$encrypted = pack('H*',$encrypted);
$key = mysql_aes_key($key);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,$key,$encrypted,MCRYPT_MODE_ECB,''),"\x00..\x1F");
}
This is a direct example of mCrypt's decrypt AES function.
I cannot see anywhere where the IV goes to decrypt this. Am I missing
something, is the IV not needed when decrypting?
It seems pretty clear from the docs:
string mcrypt_decrypt ( string $cipher , string $key , string $data ,
string $mode [, string $iv ] )
So the last argument is where the IV should go. In your current code, you are passing an empty string ('').

How to change php 5.2 mhash codes to php5.3 hash

Friends my php 5.2 codes am keeping my password like this
echo '<br>'.base64_encode(mhash(MHASH_MD5,'test'));
result CY9rzUYh03PK3k6DJie09g==
In php 5.3 mhash extension is obsoleted by Hash like I saw in there documentation. So I tried like this. But its giving wrong result.
echo '<br>'.base64_encode(hash(MD5,'test'));
result MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
Please help me to convert my 5.2 mhash codes to 5.3.
Thanks
Actually, they are the same, only in a different format.
The first one is binary data, while the second one is hexadecimal.
You can convert the first one to the second using this function:
$second_hash = bin2hex ($first_hash);
Or the other way around:
$first_hash = hex2bin ($second_hash);
Update
Add this function:
define('HEX2BIN_WS', " \t\n\r");
function hex2bin($hex_string) {
$pos = 0;
$result = '';
while ($pos < strlen($hex_string)) {
if (strpos(HEX2BIN_WS, $hex_string{$pos}) !== FALSE) {
$pos++;
} else {
$code = hexdec(substr($hex_string, $pos, 2));
$pos = $pos + 2;
$result .= chr($code);
}
}
return $result;
}
If you want to update obsolete mhash() method to hash_hmac() method using sha1, simply replace :
mhash(MHASH_SHA1, $data, $key)
into
hash_hmac('sha1', $data,$key,true)
In my context i was faced to old piece of code
base64_encode(mhash(MHASH_SHA1, $data, $key));
which i replaced by
base64_encode(hash_hmac('sha1', $data,$key,true));
I hope it could help.
mhash(MHASH_MD5, 'FOOBAR'); // what you have
pack('H*', hash(MD5, 'FOOBAR')) // what you accepted
pack('H*', md5('FOOBAR')); // ...
md5('FOOBAR', true); // what you could/should have used
I know this question is rather old but today I had the same problem. Based on this post I was able to find a shorter and I guess more performant way which is worth sharing in my opinion.

Categories