Skip to content

Instantly share code, notes, and snippets.

@pmeulen
Last active February 9, 2021 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmeulen/29da05c99165e3e4bfff8d7fbbb03fde to your computer and use it in GitHub Desktop.
Save pmeulen/29da05c99165e3e4bfff8d7fbbb03fde to your computer and use it in GitHub Desktop.
Functions for encrypting and decrypting data with RSA public key crypto using the PHP openssl_* functions.
<?php
/**
* Encrypt $plaintext using $rsa_public_key
*
* To decrypt the data the RSA private that corresponds to the $rsa_public_key is required.
*
* Because public key crypto is not suitable for arbitrary length data, encryption is done in two steps
* 1. Generate a random symmetric key and encrypt the plaintext with that key
* 2. Encrypt the symmetric key with the public key
*
* @param $plaintext string to be encrypted
* @param $rsa_public_key - PEM RSA PUBLIC KEY or PEM CERTIFICATE
* @return array with encrypted plaintext on success, false on error
*/
function encrypt($plaintext, $rsa_public_key)
{
if ( !is_string($plaintext) || !is_string($rsa_public_key)) {
// Invalid argument
return false;
}
// Use AES-256 in GCM
$symmetric_algorithm = 'aes-256-gcm';
// Generate initialisation vector for the symmetric encryption algorithm
$iv_length = openssl_cipher_iv_length($symmetric_algorithm);
if (false === $iv_length) {
// Error generating key
return false;
}
$iv = openssl_random_pseudo_bytes($iv_length);
if (false === $iv) {
// Error generating key
return false;
}
// Generate a 256 bits AES key
$secret_key = openssl_random_pseudo_bytes(256 / 8);
if (false === $secret_key) {
// Error generating key
return false;
}
// Encrypt plaintext
$tag = '';
$ciphertext = openssl_encrypt($plaintext, $symmetric_algorithm, $secret_key, 0, $iv, $tag);
if (false === $ciphertext) {
// Encryption failed
return false;
}
// Encrypt symmetric key
$rsa_public_key_handle = openssl_pkey_get_public($rsa_public_key);
if (false === $rsa_public_key_handle) {
// Reading RSA public key failed
return false;
}
$encrypted_key = '';
$res = openssl_public_encrypt($secret_key, $encrypted_key, $rsa_public_key_handle, OPENSSL_PKCS1_OAEP_PADDING);
if (false === $res) {
// Key encryption failed
openssl_pkey_free($rsa_public_key_handle);
return false;
}
openssl_pkey_free($rsa_public_key_handle);
return array(
'algorithm' => $symmetric_algorithm,
'iv' => base64_encode($iv),
'tag'=> base64_encode($tag),
'ciphertext' => base64_encode($ciphertext),
'encrypted_key' => base64_encode($encrypted_key)
);
}
/**
* Decrypt a $ciphertext that was created with the encrypt() function
*
* @param $ciphertext array created using encrypt() function
* @param $rsa_private_key - PEM RSA PRIVATE KEY
* @return string with decrypted ciphertext, false on error
*/
function decrypt($ciphertext, $rsa_private_key) {
if ( !is_array($ciphertext) || !is_string($rsa_private_key)) {
// Invalid argument
return false;
}
if ( !isset($ciphertext['algorithm'], $ciphertext['iv'], $ciphertext['tag'], $ciphertext['ciphertext'], $ciphertext['encrypted_key']) ) {
// Invalid argument
return false;
}
// Use AES-256 in GCM
if ( $ciphertext['algorithm'] != 'aes-256-gcm' ) {
// Unsupported algorithm
return false;
}
$algorithm = $ciphertext['algorithm'];
$iv = base64_decode( $ciphertext['iv'], true );
$tag = base64_decode( $ciphertext['tag'], true );
$encrypted_key = base64_decode( $ciphertext['encrypted_key'], true );
$decoded_ciphertext = base64_decode( $ciphertext['ciphertext'], true );
$rsa_private_key_handle = openssl_pkey_get_private( $rsa_private_key );
if (false === $rsa_private_key_handle) {
// Error loading private key
return false;
}
$secret_key = '';
$res=openssl_private_decrypt( $encrypted_key, $secret_key, $rsa_private_key_handle,OPENSSL_PKCS1_OAEP_PADDING );
if (false === $res) {
openssl_pkey_free($rsa_private_key_handle);
return false;
}
openssl_pkey_free($rsa_private_key_handle);
$plaintext = openssl_decrypt( $decoded_ciphertext, $algorithm, $secret_key, 0, $iv, $tag );
if (false === $plaintext) {
// Decryption failed
return false;
}
return $plaintext;
}
// Data to be encrypted
$test_plaintext = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet suscipit ipsum. Morbi pretium, elit a aliquam venenatis, diam mauris blandit ipsum, id posuere mauris urna eu libero. Fusce volutpat id odio at convallis. Quisque sodales maximus est vel efficitur. Proin id justo cursus, porta arcu et, porttitor tortor. In fringilla orci non lectus venenatis, sit amet vehicula leo vulputate. Aliquam vulputate ultricies velit eu tempus. In eu sapien eros. In rutrum neque in orci hendrerit congue. Phasellus in efficitur leo. Nunc consequat erat augue, in sodales est accumsan eget. Quisque quis ornare sem. Maecenas condimentum, lorem sit amet.";
$test_rsa_private_key=<<<RSA_PRIVATE_KEY
-----BEGIN RSA PRIVATE KEY-----
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
5ni9gQKCAQEAzL+UiWPmRDFDA383Jlms9gYhbDR8FWiyW4KJNZhQq3IO6S7hqZct
HF2lG+qgKKGkm1+jFAaQiGbAFYLQIBtNodEGo5br8xYblnAV8obl/wM0uHbHNqSv
O5hg3oNOPyGTJu/YNDSeacPYLoRkayJyZ8NAnxBYWIEqngwFGGFwVreVcpFmOzCS
2KTi6LDyo1Kb1Z8Nm/pSZLqCHh7qGV1LY2I+mcXm8MPyNzX6R+PrGU0T9kjeRImY
N1a6TBJJ5vEkPB2AYAbXOVtunj7smQIQmS3tMY51oErSkYotZcyzkYaeG1TWpPh6
5Wdogou+q9B0LOZTn7Bjeq+s/n7Tq8BXCQKCAQBeJWBMQx2ehbJcd3L+uF88sAcZ
Kg2WBJCYwvEY3pOzysW6UA/7VjSfSuR8d1Zl9uDsZHH71+OB591+isPXR2h0/wWP
52iBW2HXVMlHks5DUEPGJSBypN7uCH6UEV0R8SxmJIj+qR3xd+asayTKdZ4Y2kC8
UWsuomapGnkW+o1huxwvFd19t415+at0eU0mazyOVS5wwPHPSbWlVOOG6fWEHeVj
KdTbCDiEEHMfLfPCr9I/EKrCahOIdAe0AVONvp6ko58DnRIIYSgOAb6F80K1PQ3v
L8Iy5XBC+r/6qs6davFMso5LqDzwaTnIqzD5CSaqy1/qgp03MNnzbpA4c2r2
-----END RSA PRIVATE KEY-----
RSA_PRIVATE_KEY;
// RSA Public key in PEM format
$test_rsa_public_key=<<<RSA_PUBLIC_KEY
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu9Z0jMDV3KfMV2C9I3d7
9QDVuFtQTCIGHqZQJtraz6+6IEG6jUafNtDf3LYjJOBKB4QD1dASfzPZPP7d1pcs
+uof+SUAJ+UqtV5k/SbPEKQLUAQoetNMuA4JWr64Dna7Hiv3v/MjaAikYUwkbVOQ
e33V4BChrOQZTmAWrgy4F0e2s79CPzUL4C3OCHpgWq4zSEOHQDsNXHfnGNOHXN73
iearA+MvR601u5UXSKibOCQGRAdsGf+OaPyWT2k1U1uQ0yoBN3lBjgFU1YMHA1w+
AeIbS+a7Ddh/uEu5I6sk0P3D5yXTganoEtOkft6HKAan7unFb85qVKRTfBGwOwg+
xCD689KLhznu3u0z+4qnjtvFCRQyc0DMwTV+ITyYjp7rcXS/arTuJQ67QZIwevaE
o7EiEqNIC3RicPgd4y8Klt0E6SLMMkyFv/o+ez9Y/wNkrSDROaYwpEko7rgxtnPW
iujh4yz7FBq0ZrGRclfwinvm9GSqMVqB/reGRLeGKqJ1Z/CDCLx9432R1yKyTIa4
vmDkexbldg5pyyCwfYPgXKFfOepkfEMxrqVs4lTxDmvjOa2hHP4KUwOjZIAXpSnw
qbP8ufor/kz0/Yi3a7j/pkutXtjm6t4kAKwN/wcMcPAwBBeNfFiP75pqjcjYnSQE
ZveiwwfkcpIUZNWwrQJUiQkCAwEAAQ==
-----END PUBLIC KEY-----
RSA_PUBLIC_KEY;
$test_ciphertext = encrypt( $test_plaintext, $test_rsa_public_key);
if (false === $test_ciphertext) {
echo 'Encryption failed';
return false;
}
print_r( $test_ciphertext );
$test_decrypted = decrypt( $test_ciphertext, $test_rsa_private_key);
if (false === $test_decrypted) {
echo 'Decryption failed';
return false;
}
echo $test_decrypted;
echo ($test_plaintext == $test_decrypted) ? "\n\nSuccess\n" : "\n\nFailed:\n";
return 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment