I wrote a simple API with PHP that return an encypted string (using openssl_encrypt() function) to the clients/consumers.
When the consumer receives the encrypted string, it can't decrypt it correctly (obviously using the same key) because openssl_decrypt() function return false...
What's wrong?
/* Encryption on server */
$cipher = "aes-128-gcm";
$key = 'my-super-secret-key';
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$enc_string = openssl_encrypt($my_string, $cipher, $key, 0, $iv, $tag);
/* Decryption on client */
$cipher = "aes-128-gcm";
$key = 'my-super-secret-key';
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$my_string = openssl_decrypt($enc_string, $cipher, $key, 0, $iv, $tag);
$tag = NULL;
$start_string = 'The quick brown fox';
/* Encryption on server */
$cipher = "aes-128-gcm";
$key = 'my-super-secret-key';
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$enc_string = openssl_encrypt($start_string, $cipher, $key, 0, $iv, $tag);
echo $enc_string . PHP_EOL;
/* Decryption on client */
$cipher = "aes-128-gcm";
$key = 'my-super-secret-key';
$ivlen = openssl_cipher_iv_length($cipher);
#$iv = openssl_random_pseudo_bytes($ivlen);
$my_string = openssl_decrypt($enc_string, $cipher, $key, 0, $iv, $tag);
echo '>'. $my_string .'<';
OUTPUT
qqajjDNub7pylS68E7QLrHExqA==
>The quick brown fox<
You need a valid $tag and to use the same $iv and $tag when encrypting and decrypting.
So you will need to be able to securely transfer those 2 + the key to the remove machine.
Related
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 need openssl_encrypt equivalent of the below mcrypt encryption.
public function encrypt($str) {
$key = 'zXmW8rXT7id3s06m';
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$pad = $blocksize - (strlen($str) % $blocksize);
$str = $str . str_repeat(chr($pad), $pad);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = #mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$cyper_text = mcrypt_generic($td, $str);
$rt = base64_encode($cyper_text);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $rt;
}
I tried like below. But both the outputs are not same.
public function openSslEncrypt($str){
$cipher = "AES-128-CBC";
$key = 'zXmW8rXT7id3s06m';
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($str, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$ciphertext = base64_encode( $ciphertext_raw );
return $ciphertext;
}
}
I am able to find solution for this after some tries. Posting the code below.
public function openSslEncrypt($str){
$cipher = "aes-128-ecb";
$key = 'zXmW8rXT7id3s06m';
if (strlen($str) % 16) {
$pad = 16 - (strlen($str) % 16);
$str = $str . str_repeat(chr($pad), $pad);
}
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ciphertext_raw = openssl_encrypt($str, $cipher, $key, OPENSSL_RAW_DATA);
$ciphertext = base64_encode( $ciphertext_raw );
return $ciphertext;
}
}
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 need to encrypt some SOAP header fields, and I currently have the following code working in a project with PHP 5.6 version.
function getBaseEncoded($data, $key)
{
$size = $this->pkcs5_pad($data, mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB));
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$result = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $size, MCRYPT_MODE_ECB, $iv);
return trim(base64_encode($result));
}
private function pkcs5_pad($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat (chr($pad), $pad);
}
What happens is that now I have in my hands a similiar project but with PHP 7, and the function MCRYPT is deprecated and I need to switch it to OPENSSL_ENCRYPT.
The code below is my first attempt:
function getBaseEncoded($data, $key)
{
$result = openssl_encrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
return trim(base64_encode($result));
}
But I'm now receiving a SOAP error with the message
SoapFault => Could not connect to host
and it got me thinking if the problem is on my new function?
You are missing some initializator vector data.
$ivsize = openssl_cipher_iv_length('AES-128-ECB');
$iv = openssl_random_pseudo_bytes($ivsize);
$ciphertext = openssl_encrypt(
$data,
'AES-128-ECB',
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
$iv
);
echo encrypt_openssl($data, $key);
function encrypt_openssl($msg, $key, $iv = null) {
$iv_size = openssl_cipher_iv_length('AES-128-ECB');
if (!$iv) {
$iv = openssl_random_pseudo_bytes($iv_size);
}
$encryptedMessage = openssl_encrypt($msg, 'AES-128-ECB', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encryptedMessage);
}
I'm looking for a simple yet cryptographically strong PHP implementation of AES using Mcrypt.
Hoping to boil it down to a simple pair of functions, $garble = encrypt($key, $payload) and $payload = decrypt($key, $garble).
I'm recently learning about this subject, and am posting this answer as a community wiki to share my knowledge, standing to be corrected.
Mcrypt Documentation
It's my understanding that AES can be achieved using Mcrypt with the following constants as options:
MCRYPT_RIJNDAEL_128 // as cipher
MCRYPT_MODE_CBC // as mode
MCRYPT_MODE_DEV_URANDOM // as random source (for IV)
During encryption, a randomized non-secret initialization vector (IV) should be used to randomize each encryption (so the same encryption never yields the same garble). This IV should be attached to the encryption result in order to be used later, during decryption.
Results should be Base 64 encoded for simple compatibility.
Implementation:
<?php
define('IV_SIZE', mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
function encrypt ($key, $payload) {
$iv = mcrypt_create_iv(IV_SIZE, MCRYPT_DEV_URANDOM);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
$combo = $iv . $crypt;
$garble = base64_encode($iv . $crypt);
return $garble;
}
function decrypt ($key, $garble) {
$combo = base64_decode($garble);
$iv = substr($combo, 0, IV_SIZE);
$crypt = substr($combo, IV_SIZE, strlen($combo));
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
return $payload;
}
//:::::::::::: TESTING ::::::::::::
$key = "secret-key-is-secret";
$payload = "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered.";
// ENCRYPTION
$garble = encrypt($key, $payload);
// DECRYPTION
$end_result = decrypt($key, $garble);
// Outputting Results
echo "Encrypted: ", var_dump($garble), "<br/><br/>";
echo "Decrypted: ", var_dump($end_result);
?>
Output looks like this:
Encrypted: string(152) "4dZcfPgS9DRldq+2pzvi7oAth/baXQOrMmt42la06ZkcmdQATG8mfO+t233MyUXSPYyjnmFMLwwHxpYiDmxvkKvRjLc0qPFfuIG1VrVon5EFxXEFqY6dZnApeE2sRKd2iv8m+DiiiykXBZ+LtRMUCw=="
Decrypted: string(96) "In 1435 the abbey came into conflict with the townspeople of Bamberg and was plundered."
Add function to clean control characters (�).
function clean($string) {
return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $string);
}
echo "Decrypted: ", clean($end_result);
Sentrapedagang.com
Simple and Usable:
$text= 'Hi, i am sentence';
$secret = 'RaNDoM cHars!##$%%^';
$encrypted = simple_encrypt($text, $secret);
$decrypted = simple_decrypt($encrypted_text, $secret);
codes:
function simple_encrypt($text_to_encrypt, $salt) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, pack('H*', $salt), $text_to_encrypt, MCRYPT_MODE_CBC, $iv = mcrypt_create_iv($iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND))));
}
function simple_decrypt($encrypted, $salt) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack('H*', $salt), base64_decode($encrypted), MCRYPT_MODE_CBC, $iv = mcrypt_create_iv($iv_size=mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND)));
}
Class Mycrypt
Try using this class. Here. All you need to pass is key and string.
class MCrypt
{
const iv = 'fedcba9876543210';
/**
* #param string $str
* #param bool $isBinary whether to encrypt as binary or not. Default is: false
* #return string Encrypted data
*/
public static function encrypt($str, $key="0123456789abcdef", $isBinary = false)
{
$iv = self::iv;
$str = $isBinary ? $str : utf8_decode($str);
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? $encrypted : bin2hex($encrypted);
}
/**
* #param string $code
* #param bool $isBinary whether to decrypt as binary or not. Default is: false
* #return string Decrypted data
*/
public static function decrypt($code, $key="0123456789abcdef", $isBinary = false)
{
$code = $isBinary ? $code : self::hex2bin($code);
$iv = self::iv;
$td = mcrypt_module_open('rijndael-128', ' ', 'cbc', $iv);
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $isBinary ? trim($decrypted) : utf8_encode(trim($decrypted));
}
private static function hex2bin($hexdata)
{
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
How To Use
$var = json_encode(['name'=>['Savatar', 'Flash']]);
$encrypted = MCrypt::encrypt();
$decrypted = MCrypt::decrypt($encrypted);