PHP RSA library in server sites can generate key pairs and perform public key cryptography. Server sites expose generated public key to all clients, so asymmetric encrypt scheme protect data by using private and public keys.
If prefering to generate keys on browser clients, you can read the post Javascript RSA Generate Keys from Browser Client.
All codes here are not complicated, so you can easily understand even though you are still students in school. To benefit your learning, we will provide you download link to a zip file thus you can get all source codes for future usage.
Estimated reading time: 6 minutes
EXPLORE THIS ARTICLE
TABLE OF CONTENTS
BONUS
Source Code Download
We have released it under the MIT license, so feel free to use it in your own project or your school homework.
Download Guideline
- Prepare HTTP server such as XAMPP or WAMP in your windows environment.
- Download and unzip into a folder that http server can access.
SECTION 1
PHP RSA Library
Let’s review how RSA works. The process of encrypt and decrypt also contain key generation and key exchange. Usually, client and server sites apply distinct RSA libraries, so developers should make sure the integration.
How RSA Works?
Basically, there are 4 operational steps Key Generation, Key Exchange, Sending Encrypted Data, and Decrypting Ciphertext.
When site A generate key pairs, site A send a public key to site B. When data transmission is required, site B encrypts data before sending to site A. Site A should decrypted recevied ciphertext using a private key.
The worldwild most secure algroithm comes from three MIT mathematicians, and thus is named using the initials of three surnames.
JavaScript & PHP RSA Libraries
This example uses PHP OpenSSL Extension for server sites, and EBW-JSEncrypt for client sites. The former is a public option, while the latter one EBW-JSEncrypt derived from Stanford research is very straightforward to implement with.
SECTION 2
Server Generate Keys
We are going to go through whole process based on server generating keys. There are topics about PEM Format, Padding Scheme, and Base64 Encoding to be discussed.
RSA Cryptography
Clicking a button asks server sites to generate a key pair using PHP RSA library, and store them as files of publickey.pem and privatekey.pem in the directory data. For a public key file publickey.pem, it is of PEM format that embed key data with header —–BEGIN PUBLIC KEY—– and tailer —–END PUBLIC KEY—–.
Browser clients get the public key from servers, and show it on HTML pages.
The subsequent scenario is that a browser client enter clear text test 1234, and want to encrypt it by the public key for sending. When receiving it on server site, the server decrypt it to be clear text and store it as file cleartext in folder data.
It is to be emphasized that we send the same clear text twice, but find that two ciphertext are different. Why?
This is due to the result of padding scheme in RSA encryption. Without padding, RSA would indeed generate the same ciphertext each time. See OAEP for more details.
Client-Site RSA Library
You should include EBW-JSEncrypt library jsencrypt.min.js
first. Clicking a id="genkey"
button will force server sites to generate keys, and get back a public key to display on HTML pages.
Enter clear text and click a id="put"
button to send ciphertext to server sites for decryption. On server sites, check if the file cleartext in folder data contains test 1234 as you had entered in HTML layout.
<script src="js/jsencrypt.min.js"></script>
.....
<div class="step-block">
<button class="btn-rsa" id="genkey">Generate Keys in Server Site</button>
<p>Public Key:</p>
<textarea id="publickey"></textarea>
</div>
<div class="step-block">
<p>Clear Text:</p>
<input type="text" id="cleartext"></input>
<button class="btn-rsa" id="put">Send to server</button>
<textarea id="endata-put"></textarea>
</div>
</body>
</html>
<script>
var ajax_url = "ajax-server-s.php";
$("#genkey").on("click", function (r) {
$.post(ajax_url, { action:"genkey" }, function (r) {
$("#publickey").val(r);
});
});
$("#put").on("click", function (r) {
var obj = new JSEncrypt();
obj.setPublicKey($("#publickey").val());
var endata = obj.encrypt($("#cleartext").val());
$("#endata-put").val(endata);
// Send encrypted data
$.post(ajax_url, { action:"put", endata:$("#endata-put").val() }, function (r) {
console.log(r);
});
});
</script>
As the diagram below, server sites store generated RSA keys in files, and send a public key to browser clients, which keep it on HTML pages. When clients send encrypted data out, servers should encrypt received data using the private key to get clear text, which is stored as a file.
Server-Site RSA Library
The PHP OpenSSL Extension takes responsibility of generating keys. "private_key_bits" => 1024
define the key size. The public key retrieved from openssl_pkey_get_details()
is of Base64 format, instead of binary data.
For XAMPP in Windows, there could be a configuration issue. If happened, directly including a path in $config
may help. You can uncomment some codes as shown in programs to make some change.
When going to decrypt ciphertext from browser clients, you must decode it from Base64 into binary data, and then call openssl_private_decrypt()
to do it.
<?php
$privatefile = "data/privatekey.pem";
$publicfile = "data/publickey.pem";
$cleartextfile = "data/cleartext";
if($_POST["action"] == "genkey") {
// Create the keypair
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 1024,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$config_priv = [];
/* Uncomment these codes for Windows if configuration error
$openssl_conf = "c:/xampp/php/extras/openssl/openssl.cnf";
$config["config"] = $openssl_conf;
$config_priv["config"] = $openssl_conf;
*/
$res=openssl_pkey_new($config);
if(!$res) { echo "\nopenssl_pkey_new: " . openssl_error_string(); }
// Get private key
openssl_pkey_export($res, $privatekey, "", $config_priv);
if(!$privatekey) { echo "\nopenssl_pkey_export: " . openssl_error_string(); }
file_put_contents($privatefile, $privatekey);
// Get public key
$pkeydetails=openssl_pkey_get_details($res);
if(!$pkeydetails) { echo "\nopenssl_pkey_get_details: " . openssl_error_string(); }
$publickey=$pkeydetails["key"];
file_put_contents($publicfile, $publickey);
/* response */
echo $publickey;
}
if($_POST["action"] == "put") {
$endata = $_POST["endata"];
$privatekey = file_get_contents($privatefile);
openssl_private_decrypt(base64_decode($endata), $cleartext, $privatekey);
if(!$cleartext) { echo "\noopenssl_private_decrypt: " . openssl_error_string(); }
file_put_contents($cleartextfile, $cleartext);
}
?>
FINAL
Conclusion
We integrate a solution for both server-site scripts, PHP, and client-site script, JavaScript in HTML, instead of using Node.js. Some developers should require this approach.
Thank you for reading, and we have suggested more helpful articles here. If you want to share anything, please feel free to comment below. Good luck and happy coding!
Suggested Reading
TRY IT
Quick Experience
That is all for this project, and here is the link that let you experience the program. Please kindly leave your comments for our enhancement.
Try It Yourself
Click here to execute the source code, thus before studying the downloaded codes, you can check whether it is worthy.