On a webserver, I am trying to sign a small piece of data (an email address) with a private key. This signature will later be verified with the public key.
I've generated a secp521r1
private key like this:
openssl ecparam -name secp521r1 -genkey -noout -out privatekey.pem
On the server, I have this:
<?php
// The text between the delimiters is the exact content of the `privatekey.pem` file:
$privateKeyString = <<<EOF
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCEpSeRnA17cLc3ibVoGCJIq8D6O1JH8WMF0vRH69yANh0EkBBSQ/CT
/3BhJYiaq2WgBwYFK4EEACKhZANiAATcHva1328TBDbfhjJnnTsjfwDT7KhVQ13D
VRELzhdAeGkvubT4+FvBozhsWt+2HSRfO3bcxtEifp8rMWTchjZayr3woeHmF29I
ZjZMz+o/2341fekeE7IcE5h2HEAs9uY=
-----END EC PRIVATE KEY-----
EOF;
$hashedEmail = hash("sha512", "john@doe.com");
// This works fine:
$privateKey = openssl_pkey_get_private($privateKeyString);
$encryptedData = "";
// This fails:
$encryptionSuccess = openssl_private_encrypt($hashedEmail, $encryptedData, $privateKey, OPENSSL_PKCS1_PADDING);
?>
I printed the results of openssl_get_curve_names()
and confirmed that secp521r1
is in the list.
Using OPENSSL_NO_PADDING
instead of OPENSSL_PKCS1_PADDING
.
Executing on PHP 7.2 and 8.2 --> same outcome.
Using a secp384r1 key instead --> same outcome.
What have I screwed up? Is there a PHP setting I need to flip to use EC keys?
I ended up moving over to openssl_sign()
instead of openssl_private_encrypt()
. From what I can tell, the difference is twofold:
The former creates a full ASN.1
output in DER format, whereas the latter's output is just raw encrypted bytes.
The former takes the plaintext directly and hashes it internally, whereas the latter requires the input to already be hashed.
(I'd previously been using RSA keys and wanted to move to EC keys for a new project. openssl_private_encrypt()
works fine with RSA keys.)
$encryptedData = "";
$encryptionSuccess = openssl_sign("john@doe.com", $encryptedData, $privateKey, OPENSSL_ALGO_SHA512);