A Simple Guide to Client-Side Encryption and Decryption Using JSEncrypt and PHP

23 June, 2023

Before we begin, we need to understand what we’re trying to achieve. We’ll be setting up a system where data is encrypted on the client side (via JavaScript, using the JSEncrypt library) using a public key. This encrypted data will then be sent to the server where it can be decrypted using the corresponding private key. This way, sensitive data can be safely transmitted over the internet without the risk of exposure or man-in-the-middle attack.

Now, let’s break down the process step-by-step:

Step 1: Generate the Public and Private Keys Locally with PHP

The very first step is to generate the pair of keys — the public key and the private key. There are different ways of generating these keys. We are going to do this on the server side using PHP. The public key will be shared with the client for encryption and the private key will be securely stored on the server for decryption.

Here’s the PHP code we are going to use to generate the keys:

<?php

// Define an array with the configuration settings for the keys to be generated.
$config = array(
    "digest_alg" => "sha512", // specifies the hash function to use
    "private_key_bits" => 4096, // specifies the size of the private key to be generated
    "private_key_type" => OPENSSL_KEYTYPE_RSA, // specifies the type of the private key to be generated (OPENSSL_KEYTYPE_RSA stands for RSA key).
);

// Generate a new private and public key pair using the defined configuration settings.
// The openssl_pkey_new() function returns a resource that holds the key pair.
$res = openssl_pkey_new($config);

// Extract the private key from the generated key pair.
// The openssl_pkey_export() function extracts the private key as a string and stores it in the $privKey variable.
openssl_pkey_export($res, $privKey);

// Extract the public key from the generated key pair.
// The openssl_pkey_get_details() function returns an array with the key details, including the public key.
// Here, we're interested in the 'key' element of the array, which holds the public key.
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];

// Save the private key to a file named 'private_key.pem' for later use.
// The file_put_contents() function writes data to a file. If the file does not exist, it will be created.
file_put_contents('private_key.pem', $privKey);

// Similarly, save the public key to a file named 'public_key.pem' for later use.
file_put_contents('public_key.pem', $pubKey);
?>

You can save this code to a file named ‘generate_key.php’, and execute it with the CLI command below. (You can also upload the file to your local server and navigate to the location of the file, e.g.: http://localhost/generate_key.php)

php generate_key.php

This code will generate a pair of RSA keys with a length of 4096 bits. The keys are then saved to disk as ‘private_key.pem’ and ‘public_key.pem’ for later use.

Step 2: Encrypt the Data on the Client Side with JavaScript

The client will be given the public key we generated earlier. This will be used to encrypt any data that needs to be sent to the server.

Here’s the JavaScript code for the encryption:

// Define the encryption function with a single parameter (the data to be encrypted).
function encrypt(data) {
    var encrypt = new JSEncrypt(); // Create a new instance of the JSEncrypt library.
    var publicKey = “—–BEGIN PUBLIC KEY—– [] —–END PUBLIC KEY—–“; // Define the public key. This is the public key generated earlier.
    encrypt.setPublicKey(publicKey); // Set the public key for the encryption library.
    var encrypted = encrypt.encrypt(data); // Use the encrypt method of the library to encrypt the data.
    
    return encrypted; // Return the encrypted data.
}

In this code, we're creating a new instance of JSEncrypt and setting its public key to the one we got from the server (You can easily obtain the content of the public key file with the command: cat public_key.pem or just open it with any text editor).

Next, we call the encrypt method with the data we want to encrypt, and finally, it returns the encrypted data.

Note: The script will not work if you don’t include the JSEncrypt library on your HTML file, make sure to include it just before closing the HTML <head> tag.

You can either download the library from GitHub or use a CDN provider. As of now, the latest version available is 3.3.2, always use the latest available version.

<script src="https://cdn.jsdelivr.net/npm/jsencrypt@3.3.2/lib/index.min.js"></script>

Step 3: Decrypt the Data on the Server Side with PHP

Once the server receives the encrypted data, it will use the stored private key to decrypt it.

Here’s the PHP code to decrypt the data

<?php
  $encrypted = “JCI5InK...; // The encrypted message you received from the client (generated on step #2)
  $privKey = ‘—–BEGIN PRIVATE KEY—– [...] —–END PRIVATE KEY—–‘; // the private key used for decryption (generated on step #1)
  $privKey = openssl_pkey_get_private($privKey); // read the key
  openssl_private_decrypt(base64_decode($encrypted), $decrypted, $privKey); // decrypt data

  echo $decrypted; // This is your decrypted message
?>

In this code, we’re loading the private key and then using it with the openssl_private_decrypt function to decrypt the data. The base64_decode function is used here because the encrypted data is typically sent as a base64-encoded string.

That’s it! These steps cover the basic process of client-side encryption and server-side decryption. However, please note that for the simplicity of this article, there are a lot of details that I haven’t covered, such as error handling, key management, and ensuring secure transmission of the keys and the encrypted data. Be sure to understand these concepts fully when implementing encryption in your own applications.


Subscribe to the Newsletter

Get my latest posts and project updates by email