i have line of command
echo -n 2bRePass1234 | openssl dgst -sha1 -binary | openssl enc -base64
output : 3O3bhZbGKheK+g/M4pp18AwGqq8= (28 char)
i need to convert it php
what i tried. openssl_encrypt need $iv and $key. i just use random_bytes because dont know whats is the default value like the command above
return base64_encode(
openssl_encrypt(
sha1('testPass1234'),
'AES-128-CBC',
random_bytes(16),
OPENSSL_RAW_DATA,
random_bytes(16)
)
);
But its doest return same result as the command did.. is there any way just use default key and cipher to generate it?
Note: i put random_bytes(16) because i dont know what to fill it based on the command.
Two things ...
You are doing a dgst (digest) in your first call of openssl therefore you cannot call openssl_encrypt in your php.
By doing a digest you does not need random bytes.
There are at least 2 ways to do it in php
1) Using sha1 function
php -r "var_dump(base64_encode(pack('H*', sha1('testPass1234'))));"
string(28) "wW+fqYWyUoXq+c76j0j2mnD5Oyc="
2) Using openssl_digest function
php -r "var_dump(base64_encode(pack('H*', openssl_digest('testPass1234', 'SHA1'))));"
string(28) "wW+fqYWyUoXq+c76j0j2mnD5Oyc="
They will both return the same. The string returned from sha1 will be packed into a string of real bits and not treated as string.
PS: I saw you passed a different string in the command line sample and the php sample, but whenever passing the same string the results will be the same.
echo -n testPass1234 | openssl dgst -sha1 -binary | openssl enc -base64
wW+fqYWyUoXq+c76j0j2mnD5Oyc=
Hope it's what you whore looking for. Cheers!
Related
I'm attempting to run a bash command in a php script. Unfortunately, because the command contains a pipe to another command, it doesn't seem to work as simple as writing the actual bash command into proc_open, popen, or shell_exec. I'm trying to use openssl to decrypt an encrypted password. I have the encrypted password in a database and after I retrieve it I need to echo the encrypted pw and pipe it to openssl. This is the exact command I need to run in its basic bash format:
echo $encryptedPassword | openssl enc -base64 -d -aes-256-cbc -salt -pass pass: password -pbkdf2
Where password is the password I have chosen to use as a salt to encrypt it in the beginning which I'm obviously not going to put in the forum. I've tried to use proc_open, popen, and shell_exec and none of the info I've found online seems to work. There's very little information online for chaining commands within php which leads me to believe this may not be possible and I may have to take another approach. It seems there is a php openssl plugin, however my company is trying to keep things as basic as possible without installing additional components. I also feel like this would be good information to know for other command chaining as there won't always be a plugin to use.
Any help would be greatly appreciated.
With the following command:
note: please notice the use of printf %s instead of echo (which adds a newline at the end).
printf %s 'stringPassword' |
openssl enc -base64 -aes-256-cbc -salt -pass pass:'password' -pbkdf2
You get:
U2FsdGVkX1/PdBwO5rCJrbn5dZ5cHb9w1lH2E1LECBw=
For deciphering it you have to:
base64-decode the output of openssl.
Get the salt, which is bytes 9-16 of the base64-decoded string.
Derive a 48 bytes key using PBKDF2 with the given password, the salt and 10000 iterations of sha256 hashing (default of openssl -pbkdf2).
Get the encryption key (which is bytes 1-32) and the iv (which is bytes 33-48) from the derived key.
Get the ciphered text, which is bytes 17 through the end of the base64-decoded string.
Decrypt the ciphered text using aes-256-cbc, the encryption key and the iv.
Now, let's try to decipher it with php:
function decrypt($data, $passphrase) {
$d = unpack(
'x8/a8salt/a*data',
base64_decode( $data, true )
);
$k = unpack(
'a32key/a16iv',
openssl_pbkdf2( $passphrase, $d['salt'], 48, 10000, 'sha256' )
);
return openssl_decrypt(
$d['data'],
'aes-256-cbc',
$k['key'],
OPENSSL_RAW_DATA,
$k['iv']
);
}
var_dump( decrypt('U2FsdGVkX1/PdBwO5rCJrbn5dZ5cHb9w1lH2E1LECBw=', 'password') );
string(14) "stringPassword"
ASIDE: answering OP's initial question.
For calling the openssl command in a pipe inside php you can use shell_exec, but you SHALL prevent any potential code injection:
$cypher = 'U2FsdGVkX1/PdBwO5rCJrbn5dZ5cHb9w1lH2E1LECBw=';
$secret = 'password';
$text = shell_exec(
'echo ' . escapeshellarg($cypher) . ' | ' .
'openssl enc -d -base64 -aes-256-cbc -salt -pbkdf2 -pass pass:' . escapeshellarg($secret)
);
################
var_dump($text);
string(14) "stringPassword"
It turns out the digest algorithm for openssl changed between versions. 1.0.2 and older used md5 as the digest. Anything newer than that uses sha256. Since I was encrypting with newer openssl but decrypting with an older openssl, on the decryption side with openssl I had to specify to use sha256 with the option -md sha256. Otherwise it would try to use the older md5 digest. A very helpful link that led me to this conclusion: https://bbs.archlinux.org/viewtopic.php?id=225863
I have come accross other threads with similar questions but due to recent changes in PHP (ie. mcrypt removal), I am seeking some advice as to how I'd best go about this using OpenSSL in 2017/18.
Using echo 'this string will be encrypted' | openssl enc -aes-256-cbc -a -pass pass:123 in the Mac Terminal, I was able to password encrypt the string and would now like to pass this (as a parameter) into a server-side PHP function to decrypt.
Having studied this question, I can see that it is possible but it uses the now removed mcrypt function. Further reading in the PHP manual, I am no closer to figuring out how to reverse this encryption command into its PHP decryption equivalent.
This recent answer is what I have implemented so far, yet again, it just won't work with a Terminal generated encryption, only one which was created in PHP (not shown here).
<?php
$encrypted_string = $_GET['data'];
$password = '123';
$decrypted_data = openssl_decrypt($encrypted_string, "AES-256-CBC", $password);
print "Decrypted Data: <$decrypted_data>\n";
?>
The OpenSSL PHP manual states that either plain text or base64 encoded strings can be passed in and be decrypted. As I have used the -a flag during encryption, I would expect base64 to be passed in, thus eliminating the source as a potential reason why no decrypted data is returned.
I have taken care of URL encoding such that any + symbols produced by the encryption algorithm are replaced with their - %2B - URL-Safe equivalent as they would otherwise be turned into a space character, thus breaking the parameter string. This further ensures that the encoded input string is correctly addressed by the decryption algorithm.
Questions: Why won't my PHP function decrypt the string generated by the terminal command, although both use the same method and password? What is missing from my PHP code that would enable this to work?
Cheers everyone.
UPDATE
I am now using Terminal command:
echo 'blah' | openssl enc -aes-256-cbc -a -K B374A26A71490437AA024E4FADD5B497FDFF1A8EA6FF12F6FB65AF2720B59CCF -iv 64299685b2cc8da5
which encrypts to: Y4xelTtEJPUHytB5ARwUHQ==
I pass this to PHP using www.example.com/?data=Y4xelTtEJPUHytB5ARwUHQ==
PHP should take data param and decrypt. Currently, that function looks like this:
<?php
$encrypted_string = base64_decode($_GET['data']);
$key = 'B374A26A71490437AA024E4FADD5B497FDFF1A8EA6FF12F6FB65AF2720B59CCF';
$iv = '64299685b2cc8da5';
$output = openssl_decrypt($encrypted_string, 'AES-256-CBC', hex2bin($key), OPENSSL_RAW_DATA, hex2bin($iv));
print "Decrypted Data: <$output>\n";
?>
OpenSSL uses a proprietary KDF that you probably don't want to put the effort in to reproduce in PHP code. However, you can pass your key as pure hex instead, avoiding the KDF, by using the -K flag:
echo 'blah' | openssl enc -aes-256-cbc -K 0000000000000000000000000000000000000000000000000000000000000000
Here, the large hex string is your 256-bit key, hex encoded. This encryption operation will be compatible with your PHP.
I am using phpseclib to encode the contents of a json file using a random key as follows:
$plainkey = openssl_random_pseudo_bytes(32);
$iv = openssl_random_pseudo_bytes(16);
$payload_plain = file_get_contents("file.json");
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(256);
$cipher->setKey($plainkey);
$cipher->setIV($iv);
$enc_payload = $cipher->encrypt($payload_plain);
At this point, $enc_payload contains the ciphertext, and calling $cipher->decode on it returns the plaintext, as expected. So far so good.
The problem arises when i write this encrypted data to a file and then try to decrypt it using openssl, using a command such as the one below:
openssl enc -d -aes-256-cbc -iv 17741abad138acc10ab340aaa7c4b790 -K d96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf -in encrypted.txt -out plain.txt
whereby the values for -iv and -K have been obtained by using bin2hex on the random byte values obtained in the script above.
Running that command gives me an error and plain.txt contains a half correct / half scrambled version of the original json string.
Error:
bad decrypt
13124:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:.\crypto\evp\evp_enc.c:323:
What am i missing? I am thinking maybe the part where i use bin2hex on the key / iv is incorrect, but I have tried using the byte strings directly without any success. How is this done normally? Or am i missing anything obvious?
Thanks
It worked fine for me. My code (adapted from yours):
<?php
include('Crypt/AES.php');
$plainkey = pack('H*', 'd96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf');
$iv = pack('H*', '17741abad138acc10ab340aaa7c4b790');
$payload_plain = file_get_contents('plaintext.txt');
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(256);
$cipher->setKey($plainkey);
$cipher->setIV($iv);
$enc_payload = $cipher->encrypt($payload_plain);
file_put_contents('ciphertext.txt', $enc_payload);
I decrypted with this:
openssl enc -d -aes-256-cbc -iv 17741abad138acc10ab340aaa7c4b790 -K d96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf -nosalt -p -in encrypted.txt -out plaintext.txt
The difference is that I have -p and -nosalt. -p just prints the keys out but maybe -nosalt is what you need.
Or maybe the problem is simpler than even this. In the code snippet you posted you're not echo'ing or saving the key / iv anywhere. Maybe you're not outputting the right values.
I got the OpenSSL parameters from http://phpseclib.sourceforge.net/interop.html#aes,p1openssl,p2phpseclib
Here is the string I am submitting as text file (csr.txt) with command line
https://pastebin.com/qBLJcKQB
openssl command I am passing is:
openssl req -noout -modulus -in csr.txt | openssl md5
e199562f2e9f6a29826745d09faec3a6
Here is the php script version for getting the md5 hash
<?php
$csr = '-----BEGIN CERTIFICATE REQUEST-----
MIIBxzCCATACAQAwgYYxCzAJBgNVBAYTAlVLMQ8wDQYDVQQIDAZMb25kb24xDTAL
BgNVBAcMBEJsYWgxDjAMBgNVBAoMBUJsYWgxMQ4wDAYDVQQLDAVCbGFoMjETMBEG
A1UEAwwKSm9lIEJsb2dnczEiMCAGCSqGSIb3DQEJARYTb3BlbnNzbEBleGFtcGxl
LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsfzWjyj7zlVFlXCaGMH6
Gj3jsWV2tC6rLnRKK4x7hUaI0JriqXUQTNYKTgVhDslR1K0zrJYcaqpmwb4PrUJ/
2RY5si7QvHnndwJ3NOdHFOK8ggn1QqRvFFo4ssPpYWGY63Abj0Df9O6igEHQRQtn
5/9WkkM8evLLmS2ZYf9v6W8CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBADLYvFDq
IfxN81ZkcAIuRJY/aKZRcxSsGWwnuu9yvlAisFSp7xN3IhipnPwU2nfCf71iTe/l
SZifofNpqrnamKP90X/t/mjAgXbg4822Nda1HhbPOMx3zsO1hBieOmTQ9u03OkIZ
hkuQmljK8609PGUGcX5KeGBupZPVWJRf9ly7
-----END CERTIFICATE REQUEST-----';
$csrDetails = openssl_pkey_get_details(openssl_csr_get_public_key($csr));
echo md5($csrDetails['rsa']['n']);
?>
php script produces:
718926bb97aabc0fd1116fa25c295612
I have seen other threads which talk about excluding new line but in my case I am not using echo but rather using openssl. Why PHP's md5 is different from OpenSSL's md5?
Appreciate some assistance.
NOTE: If I drop from the command line "| openssl md5" & in the php script remove md5() then the results are identical
php script produces:
echo strtoupper(bin2hex($csrDetails['rsa']['n']));
B1FCD68F28FBCE554595709A18C1FA1A3DE3B16576B42EAB2E744A2B8C7B854688D09AE2A975104CD60A4E05610EC951D4AD33AC961C6AAA66C1BE0FAD427FD91639B22ED0BC79E777027734E74714E2BC8209F542A46F145A38B2C3E9616198EB701B8F40DFF4EEA28041D0450B67E7FF5692433C7AF2CB992D9961FF6FE96F
In the php version you are hashing the binary representation of the modulus, i.e. the binary data 0xB1FCD68F28.... With the command line version you are hashing a printable text string representation of the modulus, i.e. the string "Modulus=B1FCD68F28...". Assuming you are on a machine using an ASCII based character set, this translates to the binary data 0x4D6F64756C... Therefore you are hashing different data in each case and so you are going to get a different result.
Also it looks like openssl is adding a "\n" to the end of the output from the "openssl req ..." command. From php try running md5("Modulus=B1FCD68F28...\n"), i.e. note using " instead of ' and the \n on the end. I tried that and got "e199562f2e9f6a29826745d09faec3a6" - the same as the OpenSSL command line
Because I'm trying to convert a piece of PHP code to Python I'm trying to find out what the PHP function openssl_private_encrypt() does exactly.
I'd like to be able to reproduce what openssl_private_encrypt() generates with OpenSSL directly, but for some reason I'm not getting the same results. What is openssl_private_encrypt() doing with OpenSSL exactly?
OpenSSL's RSA_private_encrypt() is being used by PHP's openssl_private_encrypt() according to the PHP source code. The same OpenSSL method is being used by openssl rsautl -sign according to a different source. The same (default) padding -pkcs is also being used. Yet I can't seem to reproduce the same encryption result.
The following PHP code:
$key = "-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1tV0KlPGaeOnhlcYy3D5dr4Yd++Jz0puBBs8GIa4ammLqaoY
7Xo4J/jp9El3eK2GjwR82uXMNrICZKT0gU4k7LfXD5GUz5TqOfMIWSIM1mKPb67L
Xg5qfJ/8/cLY1RguzImd+ONQJ+MOtjtxE5BXq2luNL9k2Qw1aEhQR22xyzPPBwD9
0nCLhiq56lVXrG10+W9wMdNwtxTLc4hf3OF8IwEActV+Yw9xU8FuJnuAgovaFRQ2
/UC5OhPZckxhGoYJ7J5GSFBTNTuOuwyR/mGWXxgMNS/aQVOwK/+m7JWlwgOT5BdU
qL4ctk7rzRCWLdPhu0UmOxfHJMzjnqoXIWtL7wIDAQABAoIBAQDR2ryYxDDjKuBw
GBA+WmM1HMgmEDVb6ebB2CDCDIeEWwl0eJXVFDhaw4k1ebZciZURi16zLRpoq0Yv
LfsxfDYRjhtkN99XTq3mYYLcHqjPmoNmoyZBAHAAwP+OmpDYx8CfSCaqAtI/xEqQ
tEvmwm8BIAHpQLSwWH6rGUhiHcM5K953f5x10xuWSOH6xlAzdkLbjgN70aOQEbxw
703mKznw25UPspt89RFQPQDtgUnu76TzUp7jytxiyomj3h0CixTIAZd0OtF4g5kn
clNLCYSTVt2PBvlH/tDgVQ31JwLlzfrkHblTHFB4YNz49rempMGou/X+mHB4y5S1
CiN1LR4hAoGBAOxMywVgVmtPyLCFEetf9N1mWjiPpHsgmm+DxZPleQ8+G3G7Uc94
MO2ZUyEXayjK5L4ZwP/RoZGwo0j9VU1tzpRnjtpZYuRQNpqc3+VSzj3yasgaUh9H
syPyMCHn3H/9Qc4wD4hvRNtTTtESAaA0NM6zBGPOOCbYPelsbrwhcsoZAoGBAOi+
hXPKDhdw+whZZssOlSaZW42qfyGZwHkugRmSGplMHA3yrNGnRyn/CtQNA/r5fe/1
T/3XQy35+OyY7IxduPUUXMk4RAi1w61hr4PFs3MuewVEXUTus6q5gs/gZs1wK1DZ
BIFCHNfUYx6Bnq2O2Ytwvr7AiUlDOZRPddM1dRdHAoGAWiLk4pUgAek6LZNlBXrh
5b5QNfkdDdae8mC6cjL7XcQcJeMFTvWS/F8bJalQOAxE+vrJ8wtc7T0K3CG+cz2q
qlNiW4nzPhIW8h1bDpfqkhixgMkBgGsSO2j70UMnii7p9iPBGRMQmfUKQJf0xM6F
Qj9pMkUMiEy+ORcimmLL7akCgYB2EkkjT4rMi41eU/RY6OHzffM7MBZkllpVX6kw
rrT9teW5kbXoegMZJAB7SMsPJEimVf2pme3Dwj9sz7uZDebJtfXIQtoIzSUirR7c
K4x4z0iriF4EnU/aOVhKWt3sNI5U6nNlm4OEXoOWM02rYH+uRJkPrh83Ynowagst
Bb6L+wKBgQCAQpA7RytBXig/wF95qYtLnDjRAV+CoNldfAMVjB1+xvXgGWsq8jDW
bD9q+bFcGg7KQf7Lp/0VUkgB1p+bWVp+kq2XNfXgmrgzfzFsra95xPb7YJEFFoy1
o/fsQwasOd+ijJsMOWzrAG3eTIz3H3AsBJTed/tiUe5dNvVzmuj5ZA==
-----END RSA PRIVATE KEY-----";
openssl_private_encrypt("narf", $signature, $key);
echo bin2hex($signature);
Gives me:
b8a0b9ed54c4e6e7fb4da1b4180dcf8d56baf7cf4309b99c26f44079f5da
0b1566f8a6bb83d83b7a87078eb34e05b68e91e7a8279241bee16a1d003e
c3a99ebcbc1096b01f9bbe11ab1cce1ffc26ac38d8739efbf077c55ee80b
9afefb737ab816ef5b56e9120861a0fd53f36fb23bda6c545581ea220857
f055408ff7b8a2b4450a77928a9600bb6d053a22fb32d20834240953db3f
e0a31d453a9a2d956d0e7e56ca7849fde44e88c07363779e37ab53ecc7da
e5a91cef2a79232a782b56365937f6d48a351cf33036d8a15a859a47d781
09ac57e6261f8c73f44eb45e776d88182713b92aed359ec2953c01fdcf51
e59fbc4b1835cf4809d59ff95d869be9
While command line:
openssl rsautl -sign -inkey test_rsa -out data_out <<< "narf"
xxd -p data_out
Where test_rsa is the same key as in the PHP code. I get:
bc9d5dc772385965a7889a3e387b6398f3e58811aa0aee4b45a1576c08c2
7cde7e8d3e4b27d7fc350018b6c36f055c047ef9cd9aa8831a315fe5a350
ec271aaafa59f9dd9dda5b1ddf826e0f134785d9753eaabc866b0c716ce2
b7ac71a4ee79a3827cfc73c2169bff8ee7173172d8af8c9630e91d63c430
d308e15a1fb85a7b6fe257836e018102b8e55825c6a1a2413232b9a025a3
ca38e451d49cb04ad8a9be8452f213220d62711417c1e33adcededf9c172
2e87007e3fe25fba093774adfef3d3e72f4b3fa578a5a99721a002e69158
7e48e56ff5477162630739f74a385bb9e65da44821a278f6792e52c0edc8
356393e85b4692f33cd845d3a02760d4
Why aren't the results the same?
The PKCS1 padding uses some random bytes, so the encrypted output is different every time.
Both the PHP and the openssl outputs return the input string 'narf' when run through xxd -r -p|openssl rsautl -verify -inkey test_rsa.
When you use <<< "narf", the input string includes a newline character, which is absent in your PHP code.
If you instead do
echo -n narf | openssl rsautl -sign -inkey test_rsa | xxd -p
the output matches that of your PHP code.