Introduction to OpenPGP
OpenPGP is a widely used encryption standard that provides cryptographic privacy and authentication for data communication. It enables users to encrypt and sign their data, ensuring both security and integrity of the transmitted information. In this blog post, we delve into the powerful APIs provided by OpenPGP, offering code snippets and usage examples for each function to help you master these tools.
Generating a New Key Pair
Generating a new key pair is the foundation of using OpenPGP. Here’s how you can do it:
const openpgp = require('openpgp');
async function generateKey() {
const key = await openpgp.generateKey({
userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }],
curve: 'ed25519', // ECC curve name
passphrase: 'super long and hard to guess secret'
});
const privateKey = key.privateKeyArmored;
const publicKey = key.publicKeyArmored;
console.log('Generated Key Pair:', { privateKey, publicKey });
}
generateKey();
Encrypting a Message
To encrypt a message using the recipient’s public key, you can use the following code:
async function encryptMessage(publicKey, message) {
const publicKeyArmored = publicKey;
const { data: encrypted } = await openpgp.encrypt({
message: openpgp.message.fromText(message),
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys
});
console.log('Encrypted Message:', encrypted);
}
encryptMessage(publicKey, 'Hello, World!');
Decrypting a Message
Decrypting a message that was encrypted with your public key requires your private key:
async function decryptMessage(privateKey, passphrase, encryptedMessage) {
const privateKeyArmored = privateKey;
const { keys: [privateKeyObj] } =
await openpgp.key.readArmored(privateKeyArmored);
await privateKeyObj.decrypt(passphrase);
const { data: decrypted } = await openpgp.decrypt({
message: await openpgp.message.readArmored(encryptedMessage),
privateKeys: [privateKeyObj]
});
console.log('Decrypted Message:', decrypted);
}
decryptMessage(privateKey, 'super long and hard to guess secret', encryptedMessage);
Signing a Message
You can sign a message with your private key to ensure its integrity:
async function signMessage(privateKey, passphrase, message) {
const { keys: [privateKeyObj] } = await openpgp.key.readArmored(privateKey);
await privateKeyObj.decrypt(passphrase);
const { data: signed } = await openpgp.sign({
message: openpgp.cleartext.fromText(message),
privateKeys: [privateKeyObj]
});
console.log('Signed Message:', signed);
}
signMessage(privateKey, 'super long and hard to guess secret', 'This is a secret message');
Verifying a Signature
To verify a signed message, you will need the signer’s public key:
async function verifySignature(publicKey, signedMessage) {
const publicKeyArmored = publicKey;
const verified = await openpgp.verify({
message: await openpgp.cleartext.readArmored(signedMessage),
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys
});
const { valid } = verified.signatures[0];
if (valid) {
console.log('Signature is valid');
} else {
console.log('Signature is invalid');
}
}
verifySignature(publicKey, signedMessage);
Building an OpenPGP App Example
With the APIs explained above, let’s put together a simple messaging app that utilizes these functionalities:
const express = require('express');
const bodyParser = require('body-parser');
const openpgp = require('openpgp');
const app = express();
app.use(bodyParser.json());
let users = {}; // In-memory user storage
app.post('/generateKey', async (req, res) => {
const { name, email, passphrase } = req.body;
const { privateKeyArmored, publicKeyArmored } = await openpgp.generateKey({
userIDs: [{ name, email }],
curve: 'ed25519',
passphrase
});
users[email] = { privateKey: privateKeyArmored, publicKey: publicKeyArmored };
res.json({ privateKey: privateKeyArmored, publicKey: publicKeyArmored });
});
app.post('/encrypt', async (req, res) => {
const { email, message } = req.body;
const { publicKeyArmored } = users[email];
const { data: encrypted } = await openpgp.encrypt({
message: openpgp.message.fromText(message),
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys
});
res.json({ encryptedMessage: encrypted });
});
app.post('/decrypt', async (req, res) => {
const { email, passphrase, encryptedMessage } = req.body;
const { privateKeyArmored } = users[email];
const { keys: [privateKeyObj] } = await openpgp.key.readArmored(privateKeyArmored);
await privateKeyObj.decrypt(passphrase);
const { data: decrypted } = await openpgp.decrypt({
message: await openpgp.message.readArmored(encryptedMessage),
privateKeys: [privateKeyObj]
});
res.json({ decryptedMessage: decrypted });
});
app.listen(3000, () => console.log('OpenPGP app listening on port 3000!'));
With this example, you’ve built a simple backend for an application that generates key pairs, encrypts messages, and decrypts messages using OpenPGP. This allows users to communicate securely over an encrypted channel, ensuring their data remains private and intact.
Hash: a18a8e3d736a70714bbd0fc15046d5a87f3411b75cdf91b290d5e4d6b1a4ab99