I am encrypting a password in PHP, and want to decrypt it on a different box. I am having no luck and I would prefer to be able to decrypt it right from bash and echo it. Below is a snippet of a test in PHP.
$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";
$secretHash = "Testkey";
//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash);
//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);
//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";
I have tried numerous methods to decrypt it on Ubuntu, even storing the data to a file and outputting it to a file. Command tried was:
openssl aes-256-cbc -a -d -k Testkey -in foo.txt -out secrets.txt
Where foo.txt is the value returned from the PHP encryption, and secrets.txt is the output. How can I do this?
It bears repeating, as in the comments, that encryption without an IV is dangerous. In fact, the current version of PHP will issue a warning about it. IVs can be randomly generated using the openssl_random_pseudo_bytes() function, and transmitted in the clear along with the encrypted text. They don't have to be secret, the important thing is not to reuse the same key and IV combination, and have a random IV.
So, with that out of the way, if you take a look at the source for the function, it's not passing the password argument as a passphrase, but rather as the key. So for using openssl on the command line, it needs to be in hex and passed to the -K option, not the -k option. But then, you'll get an error back saying "iv undefined" so your PHP needs to be adjusted to include one:
<?php
$textToEncrypt = "My super secret information.\n";
$encryptionMethod = "AES-256-CBC";
$key = "Testkey";
$iv = openssl_random_pseudo_bytes(
openssl_cipher_iv_length($encryptionMethod)
);
$keyHex = bin2hex($key);
$ivHex = bin2hex($iv);
//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $key, 0, $iv);
//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $key, 0, $iv);
//Result
printf(
"Decrypted message: %s\n\nkeyHex=%s\nivHex=%s\nencryptedMessage=%s\n",
$decryptedMessage,
escapeshellarg($keyHex),
escapeshellarg($ivHex),
escapeshellarg($encryptedMessage)
);
Once you have these details, you can decrypt from command line (re-using PHP variable names here):
echo -n "$encryptedMessage" | openssl aes-256-cbc -d -a -A -K "$keyHex" -iv "$ivHex"
The other way around
#!/bin/bash
# create in bash keys
echo "generating private key"
openssl genrsa -out privkey.pem 2048
echo "signing private key"
openssl req -new -key privkey.pem -out certreq.csr -subj "/C=RO/ST=AB L=AB/O=None/OU=Department/CN=someweb.com"
echo "create a sign request"
openssl x509 -req -in certreq.csr -signkey privkey.pem -out newcert.pem
# end-of-bash-script
cp ./privkey.pem /path/to/apache/root/<some>
Encrypt some json file
openssl smime -encrypt -aes256 -in ./json.txt -binary -outform DER -out ./json.xxx newcert.pem
# test decrypt here in bash
# openssl smime -decrypt -in json.xxx -inform DER -inkey privkey.pem -out json.dec
Post it as binary to php
curl --request POST --data-binary #./json.xxx http://localhost/<some/>json.php
Then json.php script # apache root
<?php
$rkey = file_get_contents("/var/www/html/privkey.pem");
$pkey = file_get_contents("/var/www/html/newcert.pem");
$data = file_get_contents("php://input");
$fenc = tempnam("", "enc");
$fdec = tempnam("", "dec");
file_put_contents($fenc,$data);
// openssl_pkcs7_decrypt ($fenc , $fdec , $pkey, $rkey ); unable to coerce parameter 3 to x509 cert
system("openssl smime -decrypt -in ${fenc} -inform DER -inkey privkey.pem -out ${fdec}");
echo file_get_contents($fdec);
?>
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 am trying to decrypt some data encrypted via PHP openssl_seal. There don't seem to be any examples involving bash on the net (spent a while researching the matter), so I think this post will help others down the road as well.
As I understand it, I have to first decrypt the key used for RC4 encryption of the actual data using my private key. The data itself, as well as the RC4 key are stored in base64 format.
Data:
Y3jrrTI96HVK7aMR/LrLnCGsqlQNvpQN8TTEoClak2GHk1MMV5/Ig6CD5EuojJaI
gey79XGjf8S9IqLsJ/MxOjODSFM48D+G0lbBW9GEOUFB027pfuHDhyMoTsxjEFBG
XIz5
Envkey:
JJXy5kX9RNSd90BgRSKUX1AGZhwbzetVHKAZTv1/HCBEPGqaGvoWdxaiA8UaJAAr
mS7Sh3pbMm1GN41BYi2r4m9VONknIqn3VB+cikA7ZRxmKOVhRuJTgdjWhrCMyxls
1osAsC8lIFkLo13Z1v8IZAXKGIdyO86WHXzfQku8HAE=
Test private key (this one is crypted, non crypted added at very bottom of a question):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,CBBD77CC40F395BB
/OwGFHzIoLt4bNFMgdLp25igC8ghJhkRNghg1xpvpZISoniOC2b4oHXOJ4wvt0bj
5Giywp1iQCZUkM7qssJAFcLyTg/ycYz9WuOR5Z68h5p+lz4LnUtcCve2N/goJkwT
r5P59MybJEef27PAQYZyjiDK3eyYJRhcORzd592d81GsXoflroVzK9/eYS33IEeV
Y0grtBoOmDe4eVjDoluZXTGNu2si7SCXs6775jrDpPNMTeYLGApRacJ3TDYHyh9+
dmbaa65ARzRmWtdvvi2zoN/23oie5HUcBgRvubWM4u6LJ4HTLuAjGicpZjIlWQTe
Jex77StHO0zceic++Z9VQ+XfL4zdOHFCJpihunCU+zabqsFNZWZ44LeRul65iNIT
+3XHXezDsvuGkr5aJVvAdp1MxGIf5mO88Ga4pa0qIKFw/sLux+Otx94H45Zb1TgS
At8BU4zK0gSvAU7ea7H/Genug847vh2Up49h8ikmfdiexqnkxDO4N4GLrlDg5yYe
+YLEJyEDYa9Cg9vDV+no6oG1jC+4Fk1s9uk5uDSf4uNN5E5EsxsHS4JxvZ4xnWI7
DYbsy8XOwrrIptJvlttVNIYuobwFfDoWlf9yiAtsIKIVHhhVMgMSWc/0jPEKRmmv
NKMy6sGTEj6LGqh6R7bpeS3joccA8oAi0PjLil1Lt/bLBVAJ1JemLDCfJxjHqCmv
VfBcmF1YqxPKQl9cacUmZhozij1qDTghqIxpdQ/Y+HywGyfJtraDlYkGJ+UFgzh9
NEl1gebVhVBATrNodbUEfzJRz04/1BR2I1WPVcC93lo=
-----END RSA PRIVATE KEY-----
So I'm doing:
Decode from base64 (have tried getting data without base64, still the same result/using base64 to ensure there are no issues with encoding etc.):
base64 --decode envkey > envun
Decrypting the envkey with my private key:
openssl rsautl -decrypt -inkey private.pem -in /tmp/envun -out /tmp/envdec
Getting a decrypted binary (?) key and using it do decrypt data in RC4:
openssl enc -d -rc4 -in encrypted -out decrypted -pass file:envdec
.
.
However, what I'm getting is:
bad magic number
Any advise?
Non crypted private key:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCkBLH08f4nZBxiy2K9DXXmxeyqxcZtBIU3BjKDMO0jt2Lt4r6e
+MI/QFKVkms5iDUKaxPgwXptilR/f0KeLz7p2KbsAtDEFSPDWedd2/WYj2DYvoeF
+LskTYoWEyZsTbV7Vcm6lfzlZYggShtjlf6haHHTKo+FEp/ENmspni7n9wIDAQAB
AoGAFrTzshaCeg+ZAnBn1gZ0CSPjlOzWgKc8jhaUjacLXYN49bgLbdTAh6MvC7f+
kjNyLGQQl3ARs/KPqisDHQUrb1mPk2NBlMKk8SPf61D5VPcGyh1OwWSCSM9zg0AO
ZuBhi8RxZhkVAenBwmEAjHID/dA1wGj748uyuUMhq9noGbkCQQDZ/p/2QMGim5dc
KluTxUAtTuxtL5Cjn3rsCNvQiKbDE17zuZQD8O0lKaUIdWpmA9TTVxMXkGiPf/Lf
TApT6lVdAkEAwJ0KXjDsLc6h2lN6LEsm2siAj0fMnCLDUYaRmYB8Wz9S7JGWqE5O
AVg982FeYXxXe2mRL/cpKhbnGT8lvDQpYwJADuUlDPBzyqaS+wsx4rDxp6bi5LsB
SQzWm1YnnuIXcvDZ5hFiGbrWmVl1G1TahknwutgSR+PoIRX/BF7vvbgfSQJAIOYx
8Si2DpTuvFXp1kr31gLNQqvm3PxrFC/CCtARbZyBU3sCmrjVRhGGc128OzZ70s6T
R/gVheTnkD5i+aSHNQJAYGwKSmW7TQPZSlaHfs4vdSnOoxVpdqi/KJG3v+PPhz6R
2+8OZnjXk62VX05jMnMNnu9BMvP0CNjKIjnsOP7NoQ==
-----END RSA PRIVATE KEY-----
How it was encrypted:
$pub_key_ids = [];
$sealed = '';
$pub_key_string = file_get_contents("/usr/local/ssl/public.pem");
$pub_key = openssl_get_publickey($pub_key_string);
if ($pub_key) {
$pub_key_ids[] = $pub_key;
}
if (count($pub_key_ids)) {
if (openssl_seal($params['deployment_settings'], $sealed, $ekeys, $pub_key_ids) !== false) {
$data = base64_encode($sealed);
$envkey = base64_encode($ekeys[0]);
}
foreach ($pub_key_ids as $pub_key_id) {
openssl_free_key($pub_key_id);
}
}
As question stand for bash, there are some bashisms we could use:
All in one:
#!/bin/bash
openssl rc4 -d -in <(
base64 -i --decode <<eodatas
Y3jrrTI96HVK7aMR/LrLnCGsqlQNvpQN8TTEoClak2GHk1MMV5/Ig6CD5EuojJaIgey7
9XGjf8S9IqLsJ/MxOjODSFM48D+G0lbBW9GEOUFB027pfuHDhyMoTsxjEFBGXIz5
eodatas
) -iv 0 -K "$(
hexdump -v -e '/1 "%02X"' < <(
openssl rsautl -decrypt -inkey <(cat <<eoprivkey
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCkBLH08f4nZBxiy2K9DXXmxeyqxcZtBIU3BjKDMO0jt2Lt4r6e
+MI/QFKVkms5iDUKaxPgwXptilR/f0KeLz7p2KbsAtDEFSPDWedd2/WYj2DYvoeF
+LskTYoWEyZsTbV7Vcm6lfzlZYggShtjlf6haHHTKo+FEp/ENmspni7n9wIDAQAB
AoGAFrTzshaCeg+ZAnBn1gZ0CSPjlOzWgKc8jhaUjacLXYN49bgLbdTAh6MvC7f+
kjNyLGQQl3ARs/KPqisDHQUrb1mPk2NBlMKk8SPf61D5VPcGyh1OwWSCSM9zg0AO
ZuBhi8RxZhkVAenBwmEAjHID/dA1wGj748uyuUMhq9noGbkCQQDZ/p/2QMGim5dc
KluTxUAtTuxtL5Cjn3rsCNvQiKbDE17zuZQD8O0lKaUIdWpmA9TTVxMXkGiPf/Lf
TApT6lVdAkEAwJ0KXjDsLc6h2lN6LEsm2siAj0fMnCLDUYaRmYB8Wz9S7JGWqE5O
AVg982FeYXxXe2mRL/cpKhbnGT8lvDQpYwJADuUlDPBzyqaS+wsx4rDxp6bi5LsB
SQzWm1YnnuIXcvDZ5hFiGbrWmVl1G1TahknwutgSR+PoIRX/BF7vvbgfSQJAIOYx
8Si2DpTuvFXp1kr31gLNQqvm3PxrFC/CCtARbZyBU3sCmrjVRhGGc128OzZ70s6T
R/gVheTnkD5i+aSHNQJAYGwKSmW7TQPZSlaHfs4vdSnOoxVpdqi/KJG3v+PPhz6R
2+8OZnjXk62VX05jMnMNnu9BMvP0CNjKIjnsOP7NoQ==
-----END RSA PRIVATE KEY-----
eoprivkey
) -in <(base64 -i --decode <<eoenvkey
JJXy5kX9RNSd90BgRSKUX1AGZhwbzetVHKAZTv1/HCBEPGqaGvoWdxaiA8UaJAAr
mS7Sh3pbMm1GN41BYi2r4m9VONknIqn3VB+cikA7ZRxmKOVhRuJTgdjWhrCMyxls
1osAsC8lIFkLo13Z1v8IZAXKGIdyO86WHXzfQku8HAE=
eoenvkey
) ) )"
printf "\nResult: %s\n" $?
This could output:
A combination of genetic and environmental factors play a role in the development of schizophrenia.
Result: 0
By using functions
This could be more usefull:
#!/bin/bash
declare Data=./datas
declare Envkey=./envkey
declare PrivateKey=./privkey
b64Dec() { base64 -i --decode ; }
hxDump() { hexdump -e '/1 "%02X"' ; }
rsaDec() { openssl rsautl -decrypt -inkey $1 -in $2 ; }
rc4Dec() {
openssl rc4 -d -iv 0 -K "$1"
printf >&2 "\nResult: %s\n" $?
}
rc4Enc() {
openssl rc4 -iv 0 -K "$1"
printf >&2 "\nResult: %s\n" $?
}
declare Key="$(hxDump < <(rsaDec $PrivateKey <(b64Dec <$Envkey)))"
b64Dec <$Data | rc4Dec $Key
rc4Enc $Key <<eoGeorgOrwellQuote | base64
In our age there is no such thing as 'keeping out of politics.' All issues
are political issues, and politics itself is a mass of lies, evasions,
folly, hatred and schizophrenia.
-- George Orwell --
eoGeorgOrwellQuote
This could produce:
A combination of genetic and environmental factors play a role in the development of schizophrenia.
Result: 0
Result: 0
azaorSotoXpM/OoK+v/WnyGivBoGpd0dpDbC5H1XlHmJwV0RGt3NkqSfrUOuz42Sh7/04z2yaYi1
drngOLg2cxzPUBs0oyiWwUCnVdOMfF9an2j7N/HBg2o7Us9+B0YEFYy5oLISIRtZguZx2M6qYA9N
EJVDUG7mCL041jCszPAIKreV7PPnRCWt0MLyunv6MDSwJ3dppTUYcgXAL2vDxcIs/GYmbWh8sjgo
/t9fqxCM56a8xwUpityQh1JukHoFQyPzhOYUfNg85I2azhyLoX2OlQ==
Using openssl native command, you can do the following :
base64 --decode envkey > envun
openssl rsautl -decrypt -inkey private.pem -in envun -out envdec
KEY=$(cat envdec |hexdump -v -e '/1 "%02X"')
openssl rc4 -d -a -in encrypted -iv 0 -K "$KEY"
You have to use "-a" flag cause your content is base64 encoded.
You can use php in command line mode with "-q" to suppress the header.
php -q decrypt.php data.txt envkey private.pem
content of decrypt.php
<?php
$pkeyid=openssl_get_privatekey(file_get_contents($argv[3]));
$content=base64_decode(file_get_contents($argv[1]));
$envkey=base64_decode(file_get_contents($argv[2]));
if (openssl_open($content, $data, $envkey, $pkeyid)) {
echo "$data\n";
} else {
echo openssl_error_string()."\n";
}
openssl_free_key($pkeyid);
It will be far easier than using openssl native command.
What is the openssl command line for decrypting text encrypted using the following php code?
function encrypt($text, $key) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
This is how far I got:
"blah blah" encrypted with "password" becomes:
whSklKP6+wJdbGpiaCavFp8BiaZ6B1LZmJ0d7Nqx2nc=
I try and decrypt this with:
openssl base64 -d -in test.b64 > test.bin
openssl enc -d -aes-256-ecb -pass pass:password -in test.bin -out test.txt
And I get:
bad magic number
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
set_include_path('./phpseclib0.2.1a'); //http://phpseclib.sourceforge.net/
include('Crypt/AES.php');
$plaintext = 'PLAINTEXT';
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey('1234123412341234');
$ciphertext = $aes->encrypt($plaintext);
$fp = fopen("ciphertextAES", "wb");
fwrite($fp, $ciphertext);
fclose($fp);
---------------------------
openssl enc -aes-128-cbc -d -in ciphertextAES -out plaintext.txt -pass pass:1234123412341234 -nosalt
bad decrypt ?????????????????????????
3840:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:.\crypto\evp\evp_enc.c:466:
openssl enc -aes-128-cbc -e -in plaintext.txt -out ciphertext -nosalt -K AA
-iv AA -p
-p shows you the key and IV being used:
key=AA000000000000000000000000000000
iv =AA000000000000000000000000000000
Omit the -K and the -iv parameters and use -pass, instead, and you'll see that the password and the key are not at all the same thing. This is true regardless of whether or not the -nosalt option is used.