I am having problems using this code which I managed to get from somewhere on the internet to encrypt/decrypt data which I'll use to encode some documents via QR codes.
encrypt/decrypt works fine when I use this program.
but the problem is if I am using a valid AES 256 CBC the hashes should encrypted via this and can also be decrypted using online AES 256 CBC available on various websites using the right key and IV.
when I try the random online programs say the hash must be a multiplication of 16.
here is a sample hash in which I write my name"ZzNkMDA2VmRzQU5WU01tbFNQcE5YZz09"
here is the iv"42301-4279279-31"
and 256 bit key is "&E)H+MbQeThWmZq4t7w!z%C*F-JaNcRf"
and here is the code
function encrypt_decrypt($string, $action = 'encrypt')
{
$encrypt_method = "AES-256-CBC";
$secret_key = '&E)H+MbQeThWmZq4t7w!z%C*F-JaNcRf'; // user define private key
$secret_iv = '42301-4279279-31'; // user define secret key
$key = hash('sha256', $secret_key);
$iv = substr(hash('sha256', $secret_iv), 0, 16); // sha256 is hash_hmac_algo
if ($action == 'encrypt') {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if ($action == 'decrypt') {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
This works, you forgot base64_encode($output).
function decrypt($encrypted_string, $secretKey,$secretIv) {
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', $secretKey);
$iv = substr(hash('sha256', $secretIv), 0, 16);
return openssl_decrypt(base64_decode($encrypted_string),
$encrypt_method, $key, 0, $iv);
}
function encrypt($string,$secretKey,$secretIv){
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', $secretKey);
$iv = substr(hash('sha256', $secretIv), 0, 16);
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
return base64_encode($output);
}
Related
I was hoping someone would be able to clarify something for me. I have a class to encrypt data and I also use the code to make it into functions instead of a class. Now they use the same keys and everything but if I encrypt something using the class I cannot decrypt using the function why is this? is it one way more secure than the other?
this is the class
class Encryption {
var $secret_key;
var $key;
public function __contruct(){
$this->secret_key = 'MYSECRETKEY12345654321';
// hash
$this->key = hash('sha256', $this->secret_key);
}
public function encode($value){
$output = openssl_encrypt($value, 'AES-256-CBC', $this->key, 0, substr(hash('sha256', "0ac35e3825857c810f86e384d1ac59e8"), 0, 16));
$output = base64_encode($output);
return $output;
}
public function decode($value){
return openssl_decrypt(base64_decode($value), 'AES-256-CBC', $this->key, 0, substr(hash('sha256', "0ac35e3825857c810f86e384d1ac59e8"), 0, 16));
}
}
this is the function
function encrypt($value)
{
$secret = 'MYSECRETKEY12345654321';
$key = hash('sha256', $secret);
$output = openssl_encrypt($value, 'AES-256-CBC', $key, 0, substr(hash('sha256', "0ac35e3825857c810f86e384d1ac59e8"), 0, 16));
$output = base64_encode($output);
return $output;
}
function decrypt($value)
{
$secret = 'MYSECRETKEY12345654321';
$key = hash('sha256', $secret);
return openssl_decrypt(base64_decode($value), 'AES-256-CBC', $key, 0, substr(hash('sha256', "0ac35e3825857c810f86e384d1ac59e8"), 0, 16));
}
code example
$encrypt = new Encryption();
$private = $encrypt->encode(10);
$public = decrypt($private);//this will return false;
I'm using crypt function to create the hash from the string, but when used the salt parameter it's showing the salt parameter in plain form, I know the salt parameter is optional we can exclude that but what is the way to make the salt to not show in the plain form in the hashed string.
Example code
echo crypt('something','$5$rounds=5000$anexamplestring$');
Output for this code is
$5$rounds=5000$anexamplestring$YuRqx9rDLGE1wLc9Bp01/DetFvo6S7Bphn6TgGViCD8
Here the output starting string is same as the crypt function that looks awkward, is there any way around to fix this, or this is the default behavior?
In your case, you can't decrypt it without salt, it will be in the hash.
I do this if you need to encrypt something, then you need openssl and the string can be long, but each time a new one and you can't pick it up without a key.
function get_encrypt($str = false, $key = false)
{
if (!is_string($str)) {
return false;
}
$key = !empty($key) ?: 'b7^FV7867&f)vd6567';
$ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($str, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
$encrypttext = base64_encode($iv . $hmac . $ciphertext_raw);
return ($encrypttext);
}
function get_decrypt($str = false, $key = false)
{
$key = !empty($key) ?: 'b7^FV7867&f)vd6567';
$c = base64_decode($str);
$ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len = 32);
$ciphertext_raw = substr($c, $ivlen + $sha2len);
$decrypttext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
if (hash_equals($hmac, $calcmac)) {
return ($decrypttext);
} else {
return false;
}
}
$str = get_encrypt('something'); // out: ccxCvYCQrsCDC8LA1jrxh3OP38KzLXk5NLxIaSH2W7oDsqUSi3gsmZBq8hnVwuAfCZwt3M1lJhHjFAArHXlrcA==
get_decrypt($str); // out: something
I have forced to migrate from PHP 5.6 to 7.0+, everything is fine except the mcrypt_encrypt(), it was deprecated already as stated in php.net.
Here's my code
$json = array(
'Amount' => $amount
);
$data = json_encode($json);
function encrypt($data, $secret)
{
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
$data2 = utf8_encode($data);
$iv = utf8_encode("jvz8bUAx");
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
//Pad for PKCS7
$blockSize = mcrypt_get_block_size('tripledes', 'cbc');
//Encrypt data
$encData = mcrypt_encrypt('tripledes', $key, $data2, MCRYPT_MODE_CBC, $iv);
return urlencode(base64_encode($encData));
}
I want to replace the deprecated lines with openssl_encrypt.
function encrypt($data, $secret)
{
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
$data = utf8_encode($data);
$iv = utf8_encode("jvz8bUAx");
$method = 'AES-256-CBC';
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$encrypted = base64_encode($iv . $encrypted);
return $encrypted;
}
Error:
IV passed is only 8 bytes long, cipher expects an IV of precisely 16
bytes, padding with \0
What I am missing?
UPDATE: Adding decryption part
function decrypt($data, $secret)
{
//Generate a key from a hash
$data = urldecode($data);
$iv = utf8_encode("jvz8bUAx");
$key = md5(utf8_encode($secret), true);
// Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
$data3 = base64_decode($data);
return $data4 = mcrypt_decrypt('tripledes', $key, $data3, MCRYPT_MODE_CBC, $iv);
}
Updated
So what you are looking for is the des-ede3-cbc Openssl algorithm.
A convenient way to get a list of all your openssl algo's that are on your server is to run:
print_r(openssl_get_cipher_methods(TRUE));
This will generate a list that makes for a good reference.
It looks like there was a padding issue as well. Mcrypt adds padding during the encryption routine and the Openssl does not. So you have to add padding on the encryption side for the Openssl. We also need to force the no_padding in the openssl functions.
These functions should work for you now.
function encryptNew($data, $secret){
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
$data = utf8_encode($data);
$iv = utf8_encode("jvz8bUAx");
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8); //You key size has to be 192 bit for 3DES.
$method = 'des-ede3-cbc'; //<----Change you method to this...
//Mcrypt adds padding inside the function. Openssl does not. So we have to pad the data.
if (strlen($data) % 8) {
$data = str_pad($data, strlen($data) + 8 - strlen($data) % 8, "\0");
}
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
$encrypted = urlencode(base64_encode($encrypted)); //Added the urlencode.....
return $encrypted;
}
function decryptNew($data, $secret){
//$data = base64_decode(urldecode($data));//<--If you have raw data coming in this needs to be commented out.
$iv = utf8_encode("jvz8bUAx");
$key = md5(utf8_encode($secret), true);
// Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
$method = 'des-ede3-cbc';
return openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); //Force zero padding.
}
Hope this helps.
I am rewriting code to be compatible with PHP 7.2. Old code is
public function encryptPasswordOld($password, $salt)
{
$key = md5($salt);
$result = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $password, MCRYPT_MODE_ECB);
return base64_encode($result);
}
New code should be according to my research something like this
public function encryptPasswordNew($password, $salt)
{
$method = 'AES-256-ECB';
$ivSize = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivSize);
$key = md5($salt);
$result = openssl_encrypt($password, $method, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($result);
}
but I tried every combination of openssl_encrypt options: OPENSSL_RAW_DATA, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, OPENSSL_ZERO_PADDING, 0 and still ended up with different result as the old method returns
try to use pkcs5padding on value before encrypt. i.e.
remember the blocksize should be 8-byte based, i.e. 8/16/24 etc.
function pkcs5_pad($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr(0), $pad);
}
and encrypt option should be OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, i.e.
openssl_encrypt(pkcs5_pad($value, 16), 'aes-256-ecb', $aes_key, 3, '')
I can't for the life of me work out why when I encrypt something in PHP I can't then decrypt it in my iOS app, but PHP can decrypt iOS encrypted strings and decrypt/encrypt between itself.
PHP -> Obj-C FAILS.
Yes, I have looked across the net and the only solution I found was to use CBC in PHP which I'm already doing.
I'm using the FBEncryptor library for iOS and these are the encrypt/decrypt functions in PHP:
function encrypt($decrypted)
{
$iv = ''; for($i=0;$i<16;$i++){ $iv .= "\0";}
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $passKey, $decrypted, MCRYPT_MODE_CBC, $iv);
$ciphertext = base64_encode($ciphertext);
return $ciphertext;
}
function decrypt($encrypted)
{
$iv = ''; for($i=0;$i<16;$i++){ $iv .= "\0";}
$ciphertext = base64_decode($encrypted);
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $passKey, $ciphertext, MCRYPT_MODE_CBC, $iv);
return $plaintext;
}
From the FBEncryptor Github page (emphasis mine):
Supported encryption algorithm is AES 256 bit only.
But in your code snippet above, you're doing:
mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv);
i.e. decrypting with AES 128 bit as your cipher.
You'll need to correct your code accordingly. Other common mistakes include using mismatched padding and block cipher operation modes.
I managed to work out the problem. Was a silly mistake on my part with the pass key variable. Here is my final implementation anyway for anyone else that comes across this problem:
function encrypt($decrypted)
{
$thePassKey = "12345678901234567890123456789012";
# Add PKCS7 padding.
$str = $decrypted;
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
if (($pad = $block - (strlen($str) % $block)) < $block)
{
$str .= str_repeat(chr($pad), $pad);
}
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = ''; for($i=0;$i<$iv_size;$i++){ $iv .= "\0";}
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $thePassKey, $str, MCRYPT_MODE_CBC, $iv));
}
function decrypt($encrypted)
{
$thePassKey = "12345678901234567890123456789012";
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = ''; for($i=0;$i<$iv_size;$i++){ $iv .= "\0";}
$str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $thePassKey, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv);
# Strip PKCS7 padding.
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$pad = ord($str[($len = strlen($str)) - 1]);
if ($pad && $pad < $block && preg_match(
'/' . chr($pad) . '{' . $pad . '}$/', $str))
{
return substr($str, 0, strlen($str) - $pad);
}
return $str;
}