Last active
February 9, 2021 13:59
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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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 | |
-----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