I generate public and private keys for RSA by
openssl genrsa -des3 -out private.pem 2048
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
and use following php code to encrypt and decrypt data.
<?php
$plaintext = 'Hello';
$publicKey = openssl_pkey_get_public('file://public.pem');
$encrypted = '';
if (!openssl_public_encrypt($plaintext, $encrypted, $publicKey))
die('Failed to encrypt data');
var_dump($encrypted);
if (!$privateKey = openssl_pkey_get_private('file://private.pem', '123456789'))
die('Private Key failed');
$decrypted = '';
if (openssl_open($encrypted, $decrypted, $envelope, $privateKey) === FALSE)
die('Failed to decrypt data');
?>
it will encrypt data ,but to decrypt data it doesn't work and show Failed to decrypt data
it will show some thing like following resultstring(256) "y)ù¿5_÷q$çD±!‘[’ÓcÜC$Gèïü*ÞEÇGm>ËÂïQÄ„ð½i=é¨Zs€© |T²»Z”k( ráëµ1,r]o –Òll'T¾i¹Bò}Æ1sËèÝwœÒ„Ä–È‹\1{S'ÆY³Ïà^hŽ™©XO%f7‘Bþ®Ra.ªÜäÆô¼'©³#Ý.H9…ŒÏ\6°ÆýþÆJµ^ðŠØÆr£Ô&ü—Ý*ýÄq ƒÝcÓÚAçOmœi\Ê¿›ãB~ZP1ŒÑÔâ¨S…6—êQ–²x¥^0´Íº(d?G•ÚIWå¡Ä" Failed to decrypt data
If you're using openssl_public_encrypt() to encrypt your data, you need to use openssl_private_decrypt() to decrypt the data.
openssl_open() is for use with openssl_seal().
I'd recommend using the _open() and _seal() variants instead of the _public_encrypt() and _private_decrypt() variants -- the public key mechanisms are intended solely for session key transport and digital signatures. Public-key algorithms are intended for use on random data (or nearly-random data of message digests). Using non-random data with public key algorithms is definitely a mis-use of the algorithms.
Related
I'm working on a php program that will verify a digital signature. I'm testing with an example (valid) certificate, and decrypting the digital signature, this gives me the sha256 digest which I am trying to match:
$Cert1 = file_get_contents('CERT1/cert_array.json'); // TEST CERT DATA
$Cert1 = json_decode($Cert1, true);
$PublicKey = file_get_contents('CERT2/public_key_rsa.pem'); // CA CERT PUBLIC KEY
openssl_public_decrypt(hex2bin($Cert1['DigitalSignature']), $DecryptedDigitalSignature, $PublicKey, OPENSSL_PKCS1_PADDING); // DECRYPT SIGNATURE USING CA PUBLIC KEY
print('decrypted digital signature:' . bin2hex($DecryptedDigitalSignature) . "\n\n"); // PRINT RESULTS
This outputs the following:
decrypted digital signature:
3031300d0609608648016503040201050004200bf3dcf2340b972e97fe3c8493e11eeee01f298939734690d0b4e79e1f5701b4
There is some padding on the left, I now split this up to get the sha256 digest:
3031300d060960864801650304020105000420 // PADDING
0bf3dcf2340b972e97fe3c8493e11eeee01f298939734690d0b4e79e1f5701b4 // SHA256 DIGEST
Ok, so now I have my sha 256 digest, so I now wish to use the openssl_x509_fingerprint function on the same cert (CERT1) to create my own sha256 digest. This should match the digest that I already extracted from the cert from above. I use this code:
$Cert1 = file_get_contents('CERT1/cert.crt'); // THE CERT IN VALID x509 FORMAT
print(openssl_x509_fingerprint($Cert1, 'sha256'));
I get the following result:
d74157547fb287694b95b2533588c71f8706b0960e023fc4317f4f9a49ad2721
So, my question is, why am I getting "d74157547fb287694b95b2533588c71f8706b0960e023fc4317f4f9a49ad2721" and not "0bf3dcf2340b972e97fe3c8493e11eeee01f298939734690d0b4e79e1f5701b4"?
I have this application to encrypt a MP3 audio clip using a public key (public.pem) and then decrypt using a private key (private.key). I tried the following method but the encrypted file returns as a 0 byte file. No errors returned.
exec("openssl genrsa -out private.key 2048");
exec("openssl rsa -in private.key -out public.pem -outform PEM -pubout");
$public_key = file_get_contents('./public.pem');
$private_key = file_get_contents('./private.key');
$source = "./sample.mp3";
$dest = "./sample.mp3.enc";
$data = file_get_contents($source);
openssl_public_encrypt($data, $output, $public_key, OPENSSL_NO_PADDING);
file_put_contents($dest, $output);
How can I do this? There are PHP examples to encrypt text but not files using this private/public key way.
As commented by #Peter the datasize using RSA encryption is limited (depends on RSA keysize) to plaintext lengths of about 60 to 400 bytes only.
To solve the problem of encrypting a file (here a MP3-file of about 5 mb) you need to switch to a hybrid encryption as recommended by #Topaco.
Indeed, there are fewer examples for this in public so I wrote a very simple program that does what it promises to do.
The program generates a random encryption key (length 32 bytes for AES-256), a random initialization vector ("iv", 16 bytes long for AES CBC mode) and then encrypts the key with the public key with RSA padding PKCS1_OAEP_PADDING. It writes the encrypted key, the iv and the ciphertext to a file.
For decryption the (encrypted) key is read (256 bytes long) from the file, followed by the iv and the encrypted data. Then the encrypted key is decrypted with the private key and used for the final decryption with AES. In the end the decrypted data is written to a file and voilà - the file is playable.
NOTICE: The main problem in my code could be the loading of the complete files (e.g. original mp3-file on encryption and encrypted file on decryption side)
into memory before they get encrypted or decrypted - e.g. having an uncut mp3-file of hundreds of mb size may cause an ""out of memory error" - beware of this.
Security warning: this file comes with absolute NO exception handling and is for educational purpose only!.
The code will load the private and public keys from actual directory as well as the mp3-file processing takes place in this memory.
The output is short:
PHP OpenSSL RSA & AES CBC 256 hybrid encryption
encryption finished
decryption finished
here is the - beware of the limitations and security warning:
<?php
// hybrid encryption
// https://stackoverflow.com/questions/64693606/php-encrypt-a-file-using-public-key-and-decrypt-using-private-key
echo 'PHP OpenSSL RSA & AES CBC 256 hybrid encryption' . PHP_EOL;
// get filenames
$plainfile = "./whateverittakes.mp3";
$cipherfile = "./whateverittakes.mp3.enc";
$decryptedfile = "./whateverittakesdec.mp3";
// attention: it is a RSA PRIVATE KEY !
// key generation:
// openssl genrsa -out private.key 2048
// openssl rsa -in private.key -out public.pem -outform PEM -pubout
// load private & public key
$public_key = openssl_pkey_get_public(file_get_contents('./public.pem'));
$private_key = openssl_pkey_get_private(file_get_contents('./private.key'));
// generate random aes encryption key
$key = openssl_random_pseudo_bytes(32); // 32 bytes = 256 bit aes key
// now encrypt the aes encryption key with the public key
openssl_public_encrypt($key, $encryptedKey, $public_key, OPENSSL_PKCS1_OAEP_PADDING);
// save 256 bytes long encrypted key
file_put_contents($cipherfile, $encryptedKey);
// aes cbc encryption
// generate random iv
$iv = openssl_random_pseudo_bytes(16);
// save 16 bytes long iv
file_put_contents($cipherfile, $iv, FILE_APPEND);
$data = file_get_contents($plainfile);
$cipher = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
// save cipher
file_put_contents($cipherfile, $cipher, FILE_APPEND);
echo 'encryption finished' . PHP_EOL;
// decryption
// read the data
$handle = fopen($cipherfile, "rb");
// read 256 bytes long encryptedKey
$decryptionkeyLoad = fread($handle, 256);
// decrypt the encrypted key with private key
openssl_private_decrypt($decryptionkeyLoad, $decryptionkey, $private_key, OPENSSL_PKCS1_OAEP_PADDING);
// read 16 bytes long iv
$ivLoad = fread($handle, 16);
// read ciphertext
$dataLoad = fread($handle, filesize($cipherfile));
fclose($handle);
$decrypt = openssl_decrypt($dataLoad, 'AES-256-CBC', $decryptionkey, OPENSSL_RAW_DATA, $ivLoad);
file_put_contents($decryptedfile, $decrypt);
echo 'decryption finished' . PHP_EOL;
?>
I think good way is convert you'r file to byte after that encrypt byte and where you need it decrypt it.
Try :
How to convert base64 string into an audio mp3 file?
and after that use OpenSSL function of php for encrypt and decrypt string(byte) file with private and public key !
I think this is good resource:
https://www.geeksforgeeks.org/how-to-encrypt-and-decrypt-a-php-string/
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
phpseclib:
php code :
include('Crypt/RSA_XML.php');
$rsa = new Crypt_RSA_XML();
$rsa->loadKeyfromXML($public_key_xml);
$data = "invoice_number=1,100.00&customer_tin=674858994885&serial=ONLYPEMPSERIAL&tin=ONLYPUMPTIN&vat_1_net=2,0000&vat_1_value=3600&vat_2_net=0&vat_2_value=0&vat_3_net=0&vat_3_value=0&vat_4_net=0&vat_4_value=0&vat_5_net=0&vat_5_value=0&vat_6_net=0&vat_6_value=0&vat_7_net=0&vat_7_value=0&vat_8_net=0&vat_8_value=0&payment_mode=3&discount=200&total_gross=9562";
$plaintext = $data;
//define('CRYPT_RSA_PKCS15_COMPAT', true);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$ciphertext = base64_encode(strrev($rsa->encrypt($plaintext)));
echo "data";
echo $ciphertext; // there is encoded value getting
and
then how to decrypt encrypted data using private key:
echo $rsa->decrypt($ciphertext); // this is giving error , decryption error
actually , i want to encrypt in php and decrypt in c# ,
data encrypted successfully and when c# rsa crypto service decrypt this encrypted data then giving error message : invalid base-64 string length
$public_key_xml and $private_key_xml is defined below...
public key :
<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
private key :
<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent><P>9NiLuI9TjNvpAPQqD9ySdMX37OmEDCF02isoovt8hwPpiXcZYH4FeasNZoydRrBUOHTTRrW3xdUYGsCZI0H9tSg+gIjo/k/JhmECT7RuSgjEL7mLpusAhi1RFv81TNERGvWP8V9HtB4oZONgOpdTuNqJwhyZ3+aA3zyy7k1mKJc=</P><Q>wqJndWnlZ2i8sW8zhX9SPUddyf8E+wHek3SYynUNQ3T7zJbk+woqyjMuSImXXuZO47uBJlwskYwR+mJr/AuCR7Y0+jtByJF8RoqkY7ttdhS8CpJ9J2o5YMGcGw0JoJ16L0W6QvhY5Zxb5IAG5nuiPLDlgZYNo7+oKRcDyF+fbC0=</Q><DP>hwimhjMFsTnXV19Rk03it+Q2x8JBwS7ycyA6WSi5lPzjX5z/sefOvTtJOLV0R/gXestzehveLo1Hrflqe7d5ZN+9GMZpOVhnnGUEEVFBQjNzf56lFnmk4Fs9zaESlDr5ZBTqPgR+VygKvxlniOjMk7ZzI0sC0ikeCgA/7o1hOiE=</DP><DQ>Fpj2fBpcaSIu7kbj63b53GWBzScPs/jml6Ys6yyl6pQVfA507XSjvTAuCnv3GCyTMjud5g9DmW5y0+hDc1L+wEa2ZeslWx0RGbuVFIM5VUFZB700TLQ3jzVLY5Si7oP6IKzu0EG3SIlb3e7DXlUyY+uB6ga69K0W4BZs+QGpJ80=</DQ><InverseQ>nob08brDfoswDV8JAkGJIg5T9ktMBRzn5djbAfSorOCCVwW+iRz/hkzSs4LaeMuoC3V5AnLeTg1T7J3op67KGerRwwjXSgCKO4crs2pODcZuIMkaE8e/5Ti1O40yKl05mQaxLk/SgSAhy97HhHoiteg/ttLcrvsCcSfyyxzHT3M=</InverseQ><D>bwqYEbh7EjOa3gfIiRBtMIWFExtBD6zZ9dtH0i0FNvZpy8B38iqXirMImcohNxal0fN3BTGc/ft33sJQDABzQlaTnhLgLU1lU9aqeb1fhANjVzPuKhUbhm/2mFeNFfcyCDUDC7y3Zz19hB7BKAomjSQjZKnNAAo2z2e2T9Mzf5kV8uuYsnoum6LEvEfluQ3q3+9Ua64P0E4D2j2iaOnvpBzTCpeaBMDfWZEe19MaS40d/OrZOwlyAVPCW9RkT3948fC5KDvE0KetYDsrVApRSKzvBUQCVNmcO2o+rhMO1qKvS+zkw2VW5OxGDk/QuHuXIkCyipUEMa/DmK74hoxCaQ==</D></RSAKeyValue>
You must be using a really old version of phpseclib since phpseclib has had built in support for the XML format for quite a few years. So my first recommendation would be to upgrade to the latest version. After that you should be able to do something like this:
<?php
include('Crypt/RSA.php');
$plaintext = 'zzz';
$rsa = new Crypt_RSA();
$rsa->loadKey('<RSAKeyValue>
<Modulus>uidt3bPfWozkIkC6nHnRDbXrvjqplfCslV2zP4hKJ6sVjVnPfjMM0ueCuEDFZ9NK+kCWaPNAVhOKKwL8HmoX/7KcFLWkwSoatnrncHTH5STey+bqR1xTFY+Rubj8BZt7D9JJYyLQC46wn4ySVnLWkCZZ9+aaTriEBzGTpUzeRiUTWVprp3oXsA7ZKyn+lhZfMx1ILhcD8dnX7xFHB57jIKvPBxAdT4K7GxdgENeS76I/zmVmlF//JnmtZ/RM1WmRkx8mFmcK/Ky8gLsmIpPPltoyBWIKIf2NQH9kHqHa2gwoPg34LTutV9AACTWuiVOjqU7Gq2BHQcjovXMF8t3Wiw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>');
define('CRYPT_RSA_PKCS15_COMPAT', true);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
echo base64_encode($rsa->encrypt($plaintext));
If that doesn't work it'd help to see the .NET code you're using to decrypt. Also, if you could encrypt a string in .NET and post the public key you used to do the encryption and the ciphertext itself that'd be useful. From that I could play around with the phpseclib options until I found some combination of options that let me decrypt the string, which would, presumably, in turn, give us insight in how to encrypt the string.
I have a private key and encrypted string. Actually string has been encrypted using .NET modules. Now I need to decrypted the string . I tried in php but it throws me following error
openssl_private_decrypt(): key parameter is not a valid private key
I tried in perl but there it takes its own private key, But it need to use my own private key, which has been generated in our server.
Please suggest me on this issue to overcome. PHP ,Ruby , Perl Solution would be more helpful.
$crypttext="gKL/n5hkBg4jyjrLRqjQbf9gAS3xnbp1xmCmamPO33fW21JAJtlVQHYR6O1dOw3tfobMe/0uXm/kgivae9zHNey4Wt3UGzPwosUrx7V8zhC97AXya2tuENO1Fmc4Z8l9+UalwtUZxMGtl3Ua9DYuvxLP/TuavgRNpmG6eemGPag=";
$fp=fopen("private.pem","r");
$priv_key=fread($fp,8192);
fclose($fp);
openssl_private_decrypt(base64_decode($crypttext ),$newsource,false ) ;
echo "String decrypt : $newsource"**;
Private Key
<BitStrength>1024</BitStrength><RSAKeyValue><Modulus>t2G2WWIal1EinPn54ZPc3S1UgGTDxr6RFc+XEMR723VSg9toU8lSfTD7C26bUcbDxBwP1/1MbdQcx/dKX+7UlB5z79vrwfT89rUZGWeH7VZvuAawtHURgucyGMhqAZ9NxDEAl5Uo3nsNL9j1JlSBfeZf8pU5sf70KezqJTRsfrE=</Modulus><Exponent>AQAB</Exponent><P>82dZbOjQCJ7NV6EuVJXqPlh4FB65LBL1w9696sKFZuIr8refGwTZOY05se6oHbT9mn8OFXVA6A/wmz7oWNPk9w==</P><Q>wN8uixNk73DIF2SHb0aunnW5XxAIq3KxeQKoUTBAzL7BqXmKjk6XDnfxDbybmcT51wGhiO20lGg51zuxnsPXlw==</Q><DP>Kv4+VXZqCJvEOY5G2LoCPjDyRNuIabiPoKFfenARkDKzAJReji81D21am4tENrsZcIiwvCmR5WurXECoWchT0Q==</DP><DQ>qGRzW4O0VYVvfVUNFi9tF/aKwR/boe0CXDfgwvnRKbHGnfP67+JX6o73zFmGtQuQYpMO+OEpD4WsMmnw2z/7ww==</DQ><InverseQ>czq4+xiiVxb63ZtKwkxyJoDLFH0f18YlfFQTrEoAx7UE9HdjOjsJFpZ54g0yK3/S/yVgIXPwMcw6LU1QvqazPg==</InverseQ><D>Ktp/tWWSlzfToeFcvpVCMMGOFK73fTM9Tl6Di9yOoRtKnBuixqmuSCkxEVvYmgSb7PEt1qiPur6ttyEX1VFHhaugTr3aVhUpF+k7ULaHrCb8UymXXW3pp/yl/QOMPWuNKVv/GU3aQ3VTc3WUaYuOnaIkJk7uoYDQn0QqWtxtT60=</D></RSAKeyValue>
phpseclib, a pure PHP RSA implementation, supports XML private keys in this format. Usage example:
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('...'); // private key
echo $rsa->decrypt($ciphertext);
?>
you need to convert the key and actually use it:
$crypttext="gKL/n5hkBg4jyjrLRqjQbf9gAS3xnbp1xmCmamPO33fW21JAJtlVQHYR6O1dOw3tfobMe/0uXm/kgivae9zHNey4Wt3UGzPwosUrx7V8zhC97AXya2tuENO1Fmc4Z8l9+UalwtUZxMGtl3Ua9DYuvxLP/TuavgRNpmG6eemGPag=";
$priv_key = openssl_pkey_get_private("file://path/to/private.pem");
openssl_private_decrypt(base64_decode($crypttext ), $newsource, $priv_key ) ;
echo "String decrypt : $newsource"**;
A solution is to generate a key in the format PHP expects (.pem file, I think the format is called DER ASN.1 but I'm not sure), using openssl (under linux usually), and then convert it, still using OpenSSL, to a format that .NET can read. See this SO answer for more details.
Under Linux:
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -out public.pem -pubout
openssl req -nodes -x509 -days 3650 -subj '/CN=www.example.com/emailAddress=info#example.com' -new -key private.pem -out certificate.crt
openssl pkcs12 -export -out certificate.pfx -inkey private.pem -in certificate.crt
Under .NET:
// Get the public key
X509Certificate2 pubCertificate = new X509Certificate2("certificate.crt", "passphrase", X509Certificates.X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider public = (RSACryptoServiceProvider)(pubCertificate.PublicKey.Key);
System.Console.WriteLine(public.ToXmlString(false));
// Get the private key
X509Certificate2 privCertificate = new X509Certificate2("certificate.pfx", "passphrase", X509Certificates.X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider private = (RSACryptoServiceProvider)(privCertificate .PrivateKey);
System.Console.WriteLine(private.ToXmlString(true));