Public key (RSA) encryption & decryption in Deno

Mayank C
Tech Tonic

--

Introduction

Encryption and decryption allow two communicating parties to disguise information they send to each other. The sender encrypts, or scrambles, information before sending it. The receiver decrypts, or unscrambles, the information after receiving it. While in transit, the encrypted information is unintelligible to an intruder.

Public-key cryptography, or asymmetric cryptography, is a cryptographic system that uses a pair of keys. The keys can be used to encrypt and decrypt data. The pair of keys, a public key and a private key, are associated with an entity. Each public key is published (or freely distributed), and the corresponding private key is kept secret. Data encrypted with a public key can be decrypted only with the corresponding private key. The reverse of the scheme also works: data encrypted with a private key can be decrypted only with the corresponding public key.

Since the last few releases, Deno has been continually building support for web standard crypto APIs. Deno (as of v1.15) now has support for both RSA (asymmetric) and AES (symmetric) cryptosystems.

In this article, we’ll learn how to generate key, export key, encrypt data, and decrypt data using RSA-OAEP algorithm.

Public key cryptography

Any cryptosystem has four standard parts in the process:

  • Generate key: Generates a key pair that can be used for encryption and decryption
  • Export key: Both parts of the key pair can be exported, especially the public part as it needs to be published
  • Encryption: Encrypts data using the public key
  • Decryption: Decrypts data using the private key

Let’s see all the steps in detail along with examples.

Generate key

The RSA key pair can either be generated or imported. Usually in production grade distributed systems, the key pair would be provisioned during application startup.

To generate a key pair, crypto.subtle.generateKey function need to be used. The inputs are:

  • Name of the algorithm (RSA-OAEP)
  • Modulus length (usually 2048)
  • A hash function like SHA-1/256/384/512
  • Key is exportable or not
  • The uses of the key like encryption, decryption
const keyPair = await crypto.subtle.generateKey({
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-512",
},
true,
["encrypt", "decrypt"],
);

The generated key pair can be used as is or can also be exported for distribution (only the public part). There should be no need to export the private part of the key pair.

It’s important to note that, Deno associates the public key with encryption and private key with decryption. In other words, public key can only be used for encryption while private key can only be used for decryption.

{
publicKey: CryptoKey {
type: "public",
extractable: true,
algorithm: {
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: Uint8Array(3) [ 1, 0, 1 ],
hash: { name: "SHA-512" }
},
usages: [ "encrypt" ]
},
privateKey: CryptoKey {
type: "private",
extractable: true,
algorithm: {
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: Uint8Array(3) [ 1, 0, 1 ],
hash: { name: "SHA-512" }
},
usages: [ "decrypt" ]
}
}

Export key

To export a key pair, crypto.subtle.exportKey function need to be used. The inputs are:

  • Exported key format like raw, jwk, pkcs8, spki
  • Part of the key to export (pkcs8 is used to export private key, spki is used to export public key)

The key is available inside an ArrayBuffer (length is 1217) that can be converted to hex string if needed.

import {encode as he} from "https://deno.land/std/encoding/hex.ts";const td=(d:Uint8Array)=>new TextDecoder().decode(d);const exportedPublicKeyBuffer = await crypto.subtle.exportKey(
"pkcs8",
keyPair.publicKey,
);
const hexKey=td(he(new Uint8Array(exportedPublicKeyBuffer)));
// hexKey: 308204bd300d06092a864886f70d0101010500038204aa.....e2c143114f03c18730c7cc24aa71c07f7f02575fb9f13e6

Encrypt

To encrypt data, crypto.subtle.encrypt function need to be used. The inputs are:

  • Name of the algorithm (RSA-OAEP)
  • Public key
  • Data to encrypt (data must be ArrayBuffer or typed array)

The output is an ArrayBuffer containing encrypted data that can be viewed using Uint8Array.

const te=(s:string)=>new TextEncoder().encode(s);const text='Learning web crypto APIs in Deno';const encBuffer = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
keyPair.publicKey,
te(text)
);
const encData=new Uint8Array(encBuffer);
//encData: Uint8Array(256) [158,12,29,128,249,242,164,210,55,96,235,142,168,252,... 156 more items]

If needed, the encrypted data can also be converted to hex string:

import {encode as he} from "https://deno.land/std/encoding/hex.ts";const te=(s:string)=>new TextEncoder().encode(s);
const td=(d:Uint8Array)=>new TextDecoder().decode(d);
const encBuffer = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
keyPair.publicKey,
te(text),
);
const encData=new Uint8Array(encBuffer);
const encStr=td(he(encData));
//encStr: 032d8cf321c477daddacec647629e86c3602df5b67a0d976ff218a6bfcc1b16728a0ae625620f36eb6a5e5c8251b97c2d36c1f8167ba271c2b3e9b0ff7570422b84dbb605c9b9bb5edaf8cbd3fd620185e3ad472ef8f9a15309ad599e5ddafe7ca6f7674160b7697a6fca942d51700edb6d6bb72e1a6753fef56a70156881ca8098dade4bec314cb9b006adacb95b02ff3de672e107c76b62d574834c0d8766d09de9c7d46f12c307a781ba9d0903b868dccf801d36b71f82c4c62a34a49081a0a184ca45a7fc9784d9c31001005996cdc9beb57029fa642bd8ae1e550eea540c2dc288ead91d2487f0f2ef94fc04fcddac9d145c3c63f89e6ec1e93dc18022c

Decrypt

To decrypt data, crypto.subtle.decrypt function need to be used. The inputs are:

  • Name of the algorithm (RSA-OAEP)
  • Private key
  • Data to decrypt (data must be ArrayBuffer or typed array)

The output is an ArrayBuffer containing decrypted data that can be viewed using Uint8Array. The decrypted data can be converted to string using TextDecoder.

const td=(d:Uint8Array)=>new TextDecoder().decode(d);const decBuffer = await crypto.subtle.decrypt(
{ name: "RSA-OAEP" },
keyPair.privateKey,
encBuffer,
);
const decData=new Uint8Array(decBuffer);
const decStr=td(decData);
//decStr: Learning web crypto APIs in Deno

To know about private/symmetric key (AES) encryption/decryption, visit the article here.

--

--