I want to exchange data with other businesses using PHP/OpenSSL. Each business creates public/private keys and publishes the public key. Then, I write code to manage all that. Here is a code in PHP (mostly from php.net):
<?php
$data = "secret message";
$key = file_get_contents("bus1.pub");
// get temp file w/ write access
$plaintextfile = tempnam(sys_get_temp_dir(), 'abc');
$ciphertextfile = tempnam(sys_get_temp_dir(), 'abc');
$fp = fopen($plaintextfile, "w");
fwrite($fp, $data);
fclose($fp);
// encrypt it
if (openssl_pkcs7_encrypt($plaintextfile, $ciphertextfile, $key,
array("To" => "nighthawk#example.com", // keyed syntax
"From: HQ <hq#example.com>", // indexed syntax
"Subject" => "Eyes only"))) {
echo "encryption ok<br>";
} else
echo "failure<br>";
?>
However, I get an error (failure). I suspect that I do not generate the keys correctly using OpenSSL. Please help in how to properly generate the keys so that they can be read by PHP functions above.
This is what I tried:
openssl genrsa -out bus1.pem 2048
openssl rsa -in bus1.pem -pubout > bus1.pub
Another suggestion from php docs https://www.php.net/manual/en/function.openssl-encrypt.php.
This Is The Most Secure Way To Encrypt And Decrypt Your Data,
It Is Almost Impossible To Crack Your Encryption.
--------------------------------------------------------
--- Create Two Random Keys And Save Them In Your Configuration File ---
<?php
// Create The First Key
echo base64_encode(openssl_random_pseudo_bytes(32));
// Create The Second Key
echo base64_encode(openssl_random_pseudo_bytes(64));
?>
--------------------------------------------------------
<?php
// Save The Keys In Your Configuration File
define('FIRSTKEY','Lk5Uz3slx3BrAghS1aaW5AYgWZRV0tIX5eI0yPchFz4=');
define('SECONDKEY','EZ44mFi3TlAey1b2w4Y7lVDuqO+SRxGXsa7nctnr/JmMrA2vN6EJhrvdVZbxaQs5jpSe34X3ejFK/o9+Y5c83w==');
?>
--------------------------------------------------------
<?php
function secured_encrypt($data)
{
$first_key = base64_decode(FIRSTKEY);
$second_key = base64_decode(SECONDKEY);
$method = "aes-256-cbc";
$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);
$first_encrypted = openssl_encrypt($data,$method,$first_key, OPENSSL_RAW_DATA ,$iv);
$second_encrypted = hash_hmac('sha3-512', $first_encrypted, $second_key, TRUE);
$output = base64_encode($iv.$second_encrypted.$first_encrypted);
return $output;
}
?>
--------------------------------------------------------
<?php
function secured_decrypt($input)
{
$first_key = base64_decode(FIRSTKEY);
$second_key = base64_decode(SECONDKEY);
$mix = base64_decode($input);
$method = "aes-256-cbc";
$iv_length = openssl_cipher_iv_length($method);
$iv = substr($mix,0,$iv_length);
$second_encrypted = substr($mix,$iv_length,64);
$first_encrypted = substr($mix,$iv_length+64);
$data = openssl_decrypt($first_encrypted,$method,$first_key,OPENSSL_RAW_DATA,$iv);
$second_encrypted_new = hash_hmac('sha3-512', $first_encrypted, $second_key, TRUE);
if (hash_equals($second_encrypted,$second_encrypted_new))
return $data;
return false;
}
?>
OK. I figured out the mistake. Thanks to #towr for pointing out a debugging tool. For other readers, the solution is to generate the certificate as follows. Each business need to do this, keep the private key and publish the certificate:
openssl genrsa -out business1.pass.key 2048
openssl rsa -in business1.pass.key -out business1.key
openssl req -new -key business1.key -out business1.csr
openssl x509 -req -days 3650 -in business1.csr -signkey business1.key -out business1.crt
Related
I created a P8 format Private Key and signed data Using Java and tried to verify it using Public Key in PHP which Failed.
I created p8 file using openssl command
openssl pkcs8 -topk8 -inform PEM -outform DER -in myprivate.in.key -out myprivate.in.key.p8 -nocrypt
and Signed a Json data using
public byte[] sign(String data, String privateKeyFilePath) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException {
byte[] returnVal = null;
Signature signature = Signature.getInstance(RSA_SHA_256);
PrivateKey privateKey = getPrivateKey(privateKeyFilePath);
signature.initSign(privateKey);
signature.update(data.getBytes());
returnVal = signature.sign();
return returnVal;
}
But When I tried to verify it using Public cerificate in PHP using openssl command, it failed
$cert_path = file_get_contents(storage_path('certificates/my_in.cer'));
$pub_key = openssl_get_publickey($cert_path);
$keyData = openssl_pkey_get_details($pub_key);
$pub_key = $keyData['key'];
// $verify = openssl_x509_verify()
$verify = openssl_verify($dataSigned, $signatureDecoded, $pub_key, 'sha256WithRSAEncryption');
What am I doing wrong, Also is there a way I can Sign the data using p8 key in php!
By following this process everything is ok. Maybe it will be useful to you?
Use openssl to generate keys:
# Generate PK
openssl genpkey -algorithm RSA \
-pkeyopt rsa_keygen_bits:2048 \
-pkeyopt rsa_keygen_pubexp:65537 | \
openssl pkcs8 -topk8 -nocrypt -outform der > rsa-2048-private-key.p8
# Convert your PKCS#8 file to a plain private key
openssl pkcs8 -nocrypt -in rsa-2048-private-key.p8 -inform DER -out rsa-2048-private-key.pem
# Generate pub key
openssl rsa -in rsa-2048-private-key.pem -pubout -out rsa-2048-public-key.pem
Test pkey and sign data (index.php):
<?php
$privateKeyFile="file://".__DIR__.DIRECTORY_SEPARATOR."rsa-2048-private-key.pem";
$publicKeyFile="file://".__DIR__.DIRECTORY_SEPARATOR."rsa-2048-public-key.pem";
// Data to sign
$data = 'Hello world!';
// Test on get private key
$pkeyid = openssl_pkey_get_private($privateKeyFile);
if ($pkeyid === false) {
var_dump(openssl_error_string());
}else{
var_dump($pkeyid);
}
// Sign data
openssl_sign($data, $signature, $pkeyid);
// Free memory
openssl_free_key($pkeyid);
// Read pub key
$pubkeyid = openssl_pkey_get_public($publicKeyFile);
// Test if sign is ok
$ok = openssl_verify($data, $signature, $pubkeyid);
if ($ok == 1) {
echo "Sign OK";
} elseif ($ok == 0) {
echo "Sign NOK";
} else {
echo "Sign check error";
}
// Free memory
openssl_free_key($pubkeyid);
php -S localhost:8000, http://localhost:8000, returns:
resource(2) of type (OpenSSL key) Sign OK
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);
?>
I have a code that makes the transformation but need to do it with native PHP functions because it is not activated support for running exec:
exec("openssl pkcs8 -inform DER -in 'archivo.key' -out 'archivo.key.pem' -passin pass:'lacontrasena'");
Someone can help me translate this into native PHP functions? It can be openssl or a library.
//Updated
This is my code using der2pem function:
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN PRIVATE KEY-----\n".$pem."-----END PRIVATE KEY-----\n";
return $pem;
}
$keyfile = 'myFileDER.key';
$keyFileContent = file_get_contents($keyfile);
$pemContent = der2pem($keyFileContent);
file_put_contents('llavetemp.pem', $pemContent);
$private_key1 = openssl_pkey_get_private($pemContent);
var_dump($private_key1);
The var_dump return boolean false
You can easily use uri2x's answer and a few informations from the first google result. PEM is just the base64-encoded form of the binary DER file.
Some Metadata is added and you can do everything with it.
so if you modify the function (posted by uri2x!) to the following:
function der2pem($der_data, $type='CERTIFICATE') {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN ".$type."-----\n".$pem."-----END ".$type."-----\n";
return $pem;
}
you can now call it:
$private_key=file_get_contents('archivo.key');
file_put_contents('archivo.key.pem',der2pem($private_key,'PRIVATE KEY');
and you can transform nearly everything which needs to bee transferred in crypto-concerns:
//certificates
$private_key=file_get_contents('certificate');
echo der2pem($private_key,'CERTIFICATE');//here, certificate isn't even required because it's the default
//GPG/PGP Public Keys
$pgp_public_key=file_get_contents('pgp_public_key');
echo der2pem($private_key,'PGP PUBLIC KEY BLOCK');
//CSR
$certificate_signing_request=file_get_contents('csr');
echo der2pem($private_key,'CERTIFICATE REQUEST');
...and many others!
See dan's comment on php.net:
Use the following code to convert from DER to PEM and PEM to DER.
<?php
$pem_data = file_get_contents($cert_path.$pem_file);
$pem2der = pem2der($pem_data);
$der_data = file_get_contents($cert_path.$der_file);
$der2pem = der2pem($der_data);
function pem2der($pem_data) {
$begin = "CERTIFICATE-----";
$end = "-----END";
$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));
$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
$der = base64_decode($pem_data);
return $der;
}
function der2pem($der_data) {
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN CERTIFICATE-----\n".$pem."-----END CERTIFICATE-----\n";
return $pem;
}
I want to generate example.com.crt and example.com.pem using php. The Linux command to get the files is given:
openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes
-out example.com.crt -keyout example.com.pem
I want to get the two file contents in two string in php. What is the php equivalent code for this?
UPDATE: Please don't ask to execute the Linux command.
here another command:
<?php
// generate 2048-bit RSA key
$pkGenerate = openssl_pkey_new(array(
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA
));
// get the private key
openssl_pkey_export($pkGenerate,$pkGeneratePrivate); // NOTE: second argument is passed by reference
// get the public key
$pkGenerateDetails = openssl_pkey_get_details($pkGenerate);
$pkGeneratePublic = $pkGenerateDetails['key'];
// free resources
openssl_pkey_free($pkGenerate);
// fetch/import public key from PEM formatted string
// remember $pkGeneratePrivate now is PEM formatted...
// this is an alternative method from the public retrieval in previous
$pkImport = openssl_pkey_get_private($pkGeneratePrivate); // import
$pkImportDetails = openssl_pkey_get_details($pkImport); // same as getting the public key in previous
$pkImportPublic = $pkImportDetails['key'];
openssl_pkey_free($pkImport); // clean up
// let's see 'em
echo "\n".$pkGeneratePrivate
."\n".$pkGeneratePublic
."\n".$pkImportPublic
."\n".'Public keys are '.(strcmp($pkGeneratePublic,$pkImportPublic)?'different':'identical').'.';
?>
You could use phpseclib, a pure PHP X.509 implementation:
http://phpseclib.sourceforge.net/x509/examples.html#selfsigned
<?php
include('File/X509.php');
include('Crypt/RSA.php');
// create private key / x.509 cert for stunnel / website
$privKey = new Crypt_RSA();
extract($privKey->createKey());
$privKey->loadKey($privatekey);
$pubKey = new Crypt_RSA();
$pubKey->loadKey($publickey);
$pubKey->setPublicKey();
$subject = new File_X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
//$subject->removeDNProp('id-at-organizationName');
$subject->setPublicKey($pubKey);
$issuer = new File_X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new File_X509();
//$x509->setStartDate('-1 month'); // default: now
//$x509->setEndDate('+1 year'); // default: +1 year
$result = $x509->sign($issuer, $subject);
echo "the stunnel.pem contents are as follows:\r\n\r\n";
echo $privKey->getPrivateKey();
echo "\r\n";
echo $x509->saveX509($result);
echo "\r\n";
?>
That'll create a private key and a self-signed X.509 cert (as your CLI example does) with the private keys corresponding public key.
Execute the command with the exec() or system() function, then read the output files with file_get_contents().
There is OpenSSL extension to PHP, you should check if it is not enough for you as it would be better to use it insteaf of exec():
http://php.net/manual/en/book.openssl.php
Perhaps it's not the finest solution, but you can use exec() and file_get_contents(), something like:
exec("openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes -out example.com.crt -keyout example.com.pem");
$crtFile = file_get_contents("example.com.crt");
$pemFile = file_get_contents("example.com.pem");
Be aware file permissions and obviously file paths. Better if you add some error handling around these commands.
Read more: http://php.net/manual/en/function.exec.php
And: http://php.net/manual/en/function.file-get-contents.php
I want to generate ssh keypair from php can anyone please guide me how to do it? I have tried the shell_exec but the shell asks questions so that command does not work. I would like to specify filename and path in which to put the keys after generation.
This is based on Converting an OpenSSL generated RSA public key to OpenSSH format (PHP). Thanks shevron.
<?php
$rsaKey = openssl_pkey_new(array(
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA));
$privKey = openssl_pkey_get_private($rsaKey);
openssl_pkey_export($privKey, $pem); //Private Key
$pubKey = sshEncodePublicKey($rsaKey); //Public Key
$umask = umask(0066);
file_put_contents('/tmp/test.rsa', $pem); //save private key into file
file_put_contents('/tmp/test.rsa.pub', $pubKey); //save public key into file
print "Private Key:\n $pem \n\n";
echo "Public key:\n$pubKey\n\n";
function sshEncodePublicKey($privKey) {
$keyInfo = openssl_pkey_get_details($privKey);
$buffer = pack("N", 7) . "ssh-rsa" .
sshEncodeBuffer($keyInfo['rsa']['e']) .
sshEncodeBuffer($keyInfo['rsa']['n']);
return "ssh-rsa " . base64_encode($buffer);
}
function sshEncodeBuffer($buffer) {
$len = strlen($buffer);
if (ord($buffer[0]) & 0x80) {
$len++;
$buffer = "\x00" . $buffer;
}
return pack("Na*", $len, $buffer);
}
?>
I would use phpseclib, a pure PHP RSA implementation:
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
extract($rsa->createKey());
echo "$publickey\r\n\r\n$privatekey";
?>
Sample output:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZw== phpseclib-generated-key
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----
Source: http://phpseclib.sourceforge.net/rsa/examples.html#openssh
Has anybody tried this?
ssh-keygen -q -N place_your_passphrase_here -t rsa -f ~/.ssh/id_rsa
It's worked for me
Check the manpage of ssh-keygen to find out how to execute it without any prompts.
http://linux.die.net/man/1/ssh-keygen
This code uses only built-in PHP openssl functions.
It generates keys in a portable PEM format, suitable for use with most 3rd party software.
<?php
function generateRsaKeyPair(array $config = []): array
{
$config = array_merge([
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
], $config);
// Create the keypair
$key = openssl_pkey_new($config);
if (!$key) {
throw new RuntimeException('Unable to generate RSA key pair');
}
// Get private key
openssl_pkey_export($key, $private);
if (!$private) {
throw new RuntimeException('Unable to extract private key');
}
// Get public key
$public = openssl_pkey_get_details($key)['key'] ?? null;
if (!$public) {
throw new RuntimeException('Unable to extract public key');
}
// Free key from memory
openssl_pkey_free($key);
// Return both keys
return compact('public', 'private');
}