Using PGP Encryption with Nodejs
Tags: Encryption, Nodejs, Coding, Developer, Cryptography

What is PGP?

PGP (Pretty Good Privacy) is a cryptographic process used to encrypt and decrypt information. It combines concepts from symmetric and asymmetric key encryption, maintaining some of the best security and usability aspects of both.

One way PGP can be used is to protect the confidentiality of information. Once the information is encrypted, nobody will be able to decrypt it unless they have the right key. In practice, PGP is commonly used in sending and receiving emails, sharing information on the Dark Web, and others. This is because both on and off the Internet, there are ways to intercept information being sent, making encryption using PGP or similar critical.

On a high-level the process between a sender and receiver looks like this:

The recipient generates public and private keys. The recipient sends its public key to the sender. The sender encrypts the message using the given public key. The sender sends the encrypted message to the recipient. The recipient decrypts the message using its private key.

PGP Examples in Node.js

Now, let’s go over some examples in Node.js using the openpgp library.

We’ll go over some basic examples and show how to encrypt & decrypt large files using Node.js streams.

First, set up your Node.js project and install openpgp.js:

mkdir pgp-tutorial && cd pgp-tutorial && npm init npm i openpgp --save

Note: examples use openpgp v4.10.8

Generating keys

When generating private and public PGP keys with OpenPGP, you can define which curve to use in Elliptic-curve cryptography. In this example, we use Ed25519 for its performance and small key size. For the full list of curves, you can choose from, refer to OpenPGP.js docs.

You also need to define a passphrase used to decrypt files and the private key. In practice, this should be a strong, randomized secret generated for a single-use.

Running the above gives us our private key:

And the public key:

File Encryption

Now we can start encrypting information.

Create a text file:

echo 'This file contains secret information' > secrets.txt

Here, we act as the sender who received a public key from the intended recipient. We use their public key to encrypt the confidential information:

In the newly created encrypted-secrets.txt file, we have the contents encrypted like so:

Now, as the sender, we can send the encrypted file to the recipient.

File Decryption

Here, we act as the reciever. To decrypt the encrypted-secrets.txt file, we use our private key and passphrase:

Which logs the decrypted file contents:

This file contains secret information.

Using Streams for Large Files

If you plan on encrypting or decrypting large files, you won’t be able to fit the entire file contents in memory. In this case, you can use Node.js streams.

Here, we encrypt a large file called dataset-1mill.json using streams:

encrypt(); async function encrypt() { const encrypted = await openpgp.encrypt({ message: openpgp.message.fromText(fs.createReadStream("dataset-1mill.json")), publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys, }); let readStream = encrypted.data; let writeStream = fs.createWriteStream("encrypted-dataset.txt", { flags: "a" }); readStream.pipe(writeStream); readStream.on("end", () => console.log("done!")); }

And then, we decrypt the newly created encrypted-dataset.txt using streams: