i had to receive some data encrypted with 3DES with shared keys.
I'm using php7 and openssl_decrypt function, but I'm not able to recreate the result of the example of the documentation sent to me.
The OpenSSL command that create the data sent to me is the following:
openssl enc -des-ede3-cbc -base64 -K 17839778773fadde0066e4578710928988398877bb123789 -iv 00000000 -in D:/in.txt
Example:
string_encoded: 123456
data_to_decrypt: Ja79hWTRfBE=
I tried to decode "Ja79hWTRfBE=" with an online tool and I successfully obtain "123456".
(I used this tool: http://tripledes.online-domain-tools.com/ with input text (hex) "25aefd8564d17c11", function: 3DES, mode: CBC, key (hex) 17839778773fadde0066e4578710928988398877bb123789, iv: 00000000 )
Below my php code:
$key = "17839778773fadde0066e4578710928988398877bb123789";
$decData = openssl_decrypt(base64_decode('Ja79hWTRfBE='), 'DES-EDE3-CBC', $key, 0, "00000000");
var_dump($decData);
var_dump return me bool(false).
What am i doing wrong?
i can reproduce your goal with the following code:
<?php
$data = "123456";
$method = "DES-EDE3";
$key = "17839778773fadde0066e4578710928988398877bb123789";
$options = 0;
// transform the key from hex to string
$key = pack("H*", $key);
// encrypt
$enc = openssl_encrypt($data, $method, $key, $options);
// decrypt
$dec = openssl_decrypt($enc, $method, $key, $options);
echo "plain: ".$data." encrypted: ".$enc." decrypted: ".$dec;
set data without base64
use DES-EDE3 method
transform your key (from hex to string)
Related
For testing purposes, I wrote encrypt.bash and decrypt.bash, to prove that the encrypted data saved to encrypted.txt can successfully be decrypted.
Here are the bash files:
encrypt.bash
#!/bin/bash
message="This is my message, I hope you can see it. It's very long now."
key="sup3r_s3cr3t_p455w0rd"
echo "$message" | openssl enc \
-aes-256-ctr \
-e \
-k "$key" \
-iv "504914019097319c9731fc639abaa6ec" \
-out encrypted.txt
decrypt.bash
#!/bin/bash
key="sup3r_s3cr3t_p455w0rd"
decrypted=$(openssl enc \
-aes-256-ctr \
-d \
-k "$key" \
-iv "504914019097319c9731fc639abaa6ec" \
-in encrypted.txt)
echo "Decrypted message: $decrypted"
Running bash decrypt.bash outputs the following:
Decrypted message: This is my message, I hope you can see it. It's very long now.
Where I'm struggling is reading the encrypted.txt file with PHP and decrypting it with openssl_decrypt. As far as I can tell, I'm using all the same settings, and working with binary data correctly, but obviously I'm doing something wrong.
decrypt.php
<?php
$key = "sup3r_s3cr3t_p455w0rd";
$encrypted = file_get_contents("encrypted.txt");
$iv = hex2bin("504914019097319c9731fc639abaa6ec");
$decrypted = openssl_decrypt(
$encrypted,
"aes-256-ctr",
$key,
0,
$iv,
);
echo "Decrypted message: $decrypted";
Running php decrypt.php outputs the following:
Decrypted message: ��c�������Pb�j��
It seems so simple when boiled down like this, but I am struggling to see where the bug exists in my code.
The -k option does not specify a key, but a password. From this password, together with a randomly generated 8 bytes salt, the key is derived using the derivation function EVP_BytesToKey(). The encrypted data is returned in OpenSSL format, which consists of the ASCII encoding of Salted__, followed by the 8 bytes salt and the actual ciphertext.
A simplified PHP implementation of this key derivation function that is sufficient here is (since the IV is explicitly specified here with -iv, it is not derived along with the key):
// from: https://gist.github.com/ezimuel/67fa19030c75052b0dde278a383eda1b
function EVP_BytesToKey($salt, $password) {
$bytes = '';
$last = '';
// 32 bytes key
while(strlen($bytes) < 32) {
$last = hash('sha256', $last . $password . $salt, true); // md5 before v1.1.0
$bytes.= $last;
}
return $bytes;
}
Extracting the salt and actual ciphertext is:
$password = "sup3r_s3cr3t_p455w0rd";
$encrypted = file_get_contents("<path to enc file>");
$salt = substr($encrypted, 8, 8);
$key = EVP_BytesToKey($salt, $password);
$ciphertext = substr($encrypted, 16);
In addition, since the raw data is passed, the corresponding OPENSSL_RAW_DATA flag must be set:
$iv = hex2bin("504914019097319c9731fc639abaa6ec");
$decrypted = openssl_decrypt($ciphertext, "aes-256-ctr", $key, OPENSSL_RAW_DATA, $iv);
Note that as of OpenSSL v1.1.0 the default digest is SHA256, before MD5. The digests used in EVP_BytesToKey() must be identical for compatibility. Also be aware that EVP_BytesToKey() is considered insecure nowadays.
I have an API URL with specific access token which was encrypted with C#(Below Code) and I want to Decrypt it using PHP post request by passing access token to parameters. Can anyone help me out to solve this problem.
Thanks in Advance!!
C# Code for Encryption:
private String AES_encrypt(String Input)
{
var aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key =Convert.FromBase64String("QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE");
aes.IV = Convert.FromBase64String("hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=");
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
byte[] xXml = Encoding.UTF8.GetBytes(Input);
cs.Write(xXml, 0, xXml.Length);
}
xBuff = ms.ToArray();
}
String Output = Convert.ToBase64String(xBuff);
return Output;
}
So far I tried to decrypt it with the below code
function strippadding($string)
{
$slast = ord(substr($string, -1));
$slastc = chr($slast);
$pcheck = substr($string, -$slast);
if(preg_match("/$slastc{".$slast."}/", $string)){
$string = substr($string, 0, strlen($string)-$slast);
return $string;
} else {
return false;
}
}
function decrypt($string)
{
$key = base64_decode("DZR");
$iv = base64_decode("Shravan");
$string = base64_decode($string);
return strippadding(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, $iv));
}
Fill out the items below:
Use this key and iv that are below.
key = QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE
iv= hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=
Run some text through your AES_encrypt() function and whatever comes out paste on the next line.
encrypted text = put your encrypted text here.
$xXml = openssl_decrypt(
$Output, #openssl_decrypt works with base64 encoded data
'AES-256-CBC',
base64_decode("QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE"), #key
OPENSSL_RAW_DATA,
base64_decode("hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=") #IV
);
Now $xXml is the binary form of the input string in UTF-8 encoded.
And make sure openssl is included in your PHP build.
You have not provided me with any encrypted text to be able to test this with.
Here is what I think you need to do:
In your C# code you need to change the block size to 128 bits:
aes.BlockSize = 128;
In your C# code your IV needs to be 128 bits or 16 bytes long. It needs to equal your selected block size.
So for now this needs to be your IV:
IV = HWeR102dxMjRHZlxTqL2aA==
Your key is set for 256 bits: So here is a 256 bit key:
Key = aZUEBKSsYRKA6CGQbwFwvIS8rUnW7YA2hVMNHnnf844=
C# has functions that will automatically generate a cryptographically strong string for you of a certain length. I suggest you find these functions and learn how to use them so you can generate your own keys and IVs.
Now for the PHP portion.
You should use the OpenSSL library instead of the Mcrypt library. Mcrypt is deprecated and is no longer supported. So here is an OpenSSL solution.
Since the block size is now 128 bits and the key size is 256 bits it will now be compatible with the openssl library's AES-256-CBC function.
$key = 'aZUEBKSsYRKA6CGQbwFwvIS8rUnW7YA2hVMNHnnf844='; //256 bit key.
$iv = 'HWeR102dxMjRHZlxTqL2aA=='; //128 bit IV length. The same as the block size that is set in the C#.
function decrypt($string, $key, $iv){
$cipherText = base64_decode($string); //We are going to use raw data.
return openssl_decrypt($cipherText, 'AES-256-CBC', base64_decode($key), OPENSSL_RAW_DATA, base64_decode($iv));
//Note that I did not specify no padding in the function. By default it is PKCS#7 which is what is set in the C# code.
}
The best I can tell this should work for you. This assumption is predicated on the fact that your AES_encrypt() is working correctly and that you have OpenSSL on your machine. Which you probably do.
Hope it helps!
I'm using the openssl_encrypt / decrypt method in my website but i'm having some troubles with the $tag option
openssl_encrypt ( $data, $method, $key, $options, $iv, $tag )
openssl_decrypt ( $data, $method, $key, $options, $iv, $tag )
from http://php.net/manual/en/function.openssl-encrypt.php, the definition of tag is: The authentication tag passed by reference when using AEAD cipher mode (GCM or CCM). But i didn't understand it.
I tried it in my codes
$data = "text to be encrypted";
$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
if (in_array($cipher, openssl_get_cipher_methods())){
$encryptedData = openssl_encrypt($data,$cipher,$key,$option,$iv,$tag);
echo $encryptedData;
$decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
echo $decryptedData;
}
i got this result:
encrypted text: Vlx/yKkPhg0DpD0YKvnFKRiCh/I=
decrypted text: text to be encrypted
which is correct. but if i directly decrypt the encrypted text this way:
$data = "text to be encrypted";
$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
if (in_array($cipher, openssl_get_cipher_methods())){
$encryptedData = "Vlx/yKkPhg0DpD0YKvnFKRiCh/I=";
$decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
echo $decryptedData;
}
i'm getting:
Notice: Undefined variable: tag
if someone could explain to me why this is happening and what should be the value of $tags. thanks
The tag that PHP is complaining about is an essential aspect of AES when using GCM mode of operation. In this mode, not only does the AES block cipher get applied, but an authentication tag gets calculated as well. It is an array of bytes that represents a MAC (Message Authentication Code) that can be used to verify the integrity of the data and wen decrypting. That same tag needs to be provided to do that verification. See the Wikipedia page about Galois/Counter Mode for more details.
So in order to successfully decrypt that ciphertext, you need to capture the $tag variable resulting from the openssl_encrypt() invocation and feed it into the openssl_decrypt() invocation. You did not do that, hence the complaint about the missing tag. Note that the tag (typically) contains non-readable characters so it is more convenient to store it in a base64 encoded format.
In addition to the $tag variable, you should also provide the same value for the $iv variable to the openssl_decrypt() method as you used in the openssl_encrypt() invocation. Again, base64 encoding makes that easier.
A quick test below demonstrates all this, where I first modified your script to print more stuff and then used the provided script to decrypt:
$ php test1.php
iv base64-ed: vBKbi8c6vCyvWonV
plaintext: text to be encrypted
ciphertext base64-ed: z28spOd3UEDmj+3a8n/WK11ls7w=
GCM tag base64-ed: OIAggQCGUbPgmPN6lFjQ8g==
$ php test2.php
decrypted ciphertext: text to be encrypted
where the code for test2.php is the following:
$cipher = "aes-128-gcm";
$key = "0123456789abcdefghijklmnob123456";
$option = 0;
$iv = base64_decode("vBKbi8c6vCyvWonV");
if (in_array($cipher, openssl_get_cipher_methods())){
$encryptedData = "z28spOd3UEDmj+3a8n/WK11ls7w=";
$tag = base64_decode("OIAggQCGUbPgmPN6lFjQ8g==");
$decryptedData = openssl_decrypt($encryptedData,$cipher,$key,$option,$iv,$tag);
echo("decrypted ciphertext: ".$decryptedData."\n");
}
I use the following PHP code to decrypt my AES 128 string.
function aes128_cbc_encrypt($key, $data, $iv) {
if(16 !== strlen($key)) $key = hash('MD5', $key, true);
if(16 !== strlen($iv)) $iv = hash('MD5', $iv, true);
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
}
$password = "mypasswordonthefirstrunoftheprogram";
$salt = "mysalthereitisfinallyitturnedoutok";
$encrypted = "BxGi119ltnYVNikXSP8jMJtSNIDKoMsPfd/nUEwlgSviVRM50/UgMF36j6Cqe+I/";
echo aes128_cbc_decrypt($key, $encrypted, $iv);
RIGHT RESULT =
this is my test sentence
RESULT RETURNED =
º±h©MM®StOfthis is my test sentenceok
Furthermore I decoded the string in C# with the right key and IV succesfully, so there is no error in that.
I wonder how this come ? I did the right padding and also tried the some other methods in php but all returning garbage in front of the right answer.
$encrypted length is not correct for encrypting "this is my test sentence".
The plain text is 26 characters
The padding would be 6-bytes
The string encrypted would be 32-bytes
The encrypted data would be 32-bytes
The Base64 encrypted data would be 44-bytes
The provided Base64 encrypted data is be 64-bytes
The provided encrypted data is be 48-bytes
There are an extra 16 bytes in the encrypted data
Examing the encrypted data there are an additional 16 bytes prepended to the encrypted bata prior to Base64 encoding.
Additionally the padding is not being removed from the decrypted data.
I am new to encryption. I want to encode a string with AES 128bit encryption. I can do this in PHP:
$key = 'Hello';
$plain = 'Hello Hello Hello Hello';
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plain, MCRYPT_MODE_CBC);
echo base64_encode($cipher);
This outputs:
bzXdTNochlsQwpR9hzSSS6ihG+MYIZIDZZlF85pIXlQ=
I tried the same with openssl command line:
openssl enc -aes-128-cbc -a -nosalt -in plain.txt -out encrypted.enc -pass pass:Hello
And the string saved in encrypted.enc is:
5apwiN8MdAuJ9nEW82XMyR0H3VKpI/vWc7xV2iVjCTE=
Why is it different?
The reason why I am trying to get the same output with both PHP and command line openssl is because I will have two separate web services communicating together. One service will have PHP available so I can use that but the other one will not be using PHP so I will probably have to use openssl in command line.
You mixed up password and key. Add a -p to your openssl command line to see the actual key used and observe http://php.net/manual/en/function.mcrypt-encrypt.php string mcrypt_encrypt ( string $cipher , string $key <= key! Not password.
Edit:
You also have problems with padding. Now making your plain text 48 chars (3*128 bit=3*16 bytes) long:
$plain = 'Hello Hello Hello Hellox';
$plain .= $plain;
function hexstr($hexstr) {
// return pack('H*', $hexstr); also works but it's much harder to understand.
$return = '';
for ($i = 0; $i < strlen($hexstr); $i+=2) {
$return .= chr(hexdec($hexstr[$i] . $hexstr[$i+1]));
}
return $return;
}
$cipher = #mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hexstr('25c506a9e4a0b3100d2d86b49b83cf9a'), $plain, MCRYPT_MODE_CBC, hexstr('00000000000000000000000000000000'));
echo base64_encode($cipher);
echo "\n";
And
openssl enc -aes-128-cbc -a -iv 0 -nosalt -in plain.txt -K 25c506a9e4a0b3100d2d86b49b83cf9a -nopad
results the same:
EZjBup0sfRAkIZ2/IQ3bKHWXHG4qBVv4uyW0PnxJJWvWHanNgE1QyBHMpWoZqejR