Skip to content

Latest commit

 

History

History
196 lines (136 loc) · 4.79 KB

README.md

File metadata and controls

196 lines (136 loc) · 4.79 KB

Cipher.js for Bun, Node, and Browsers

Because you don't have to be an expert to use cryptography!

  • Keys can be 128-, 192-, or 256-bit (16, 24, or 32 bytes)
  • Plain input can be raw Uint8Arrays or (UTF-8) Strings
  • Encrypted output can be Base64UrlSafe Strings, or raw Uint8Arrays

Table of Contents

  1. Example
  2. Generate a Key
  3. Initialize the Cipher (Codec)
  4. Encrypt (Cipher) Data
  5. Decrypt (Decipher) Data
  6. Convert between Bytes, Hex, Base64, and URL-Safe Base64
  7. API
  8. Implementation Details

Example

Encrypt and Decrypt with AES-GCM.

let Cipher = require("@root/cipher");

let cipher = Cipher.create(sharedSecret);

let plainBytes = [0xde, 0xad, 0xbe, 0xef];
let encBase64UrlSafe = cipher.encrypt(plainBytes);

let originalBytes = Cipher.decrypt(encBase64UrlSafe);

Usage

Copy-and-Paste Snippets for the Masses

1. Generate a Key

// Generate a 128-bit, 192-bit, or 256-bit AES secret:
let secretBytes = new Uint8Array(16); // or 24, or 32
crypto.getRandomValues(secretBytes);

let secretHex = Cipher.utils.bytesTohex(secretBytes);

2. Initialize the Cipher (Codec)

let secretHex = process.env.APP_SECRET_KEY;

let secretBytes = Cipher.utils.hexToBytes(secretHex);
let cipher = Cipher.create(sharedSecret);

3. Encrypt (Cipher) Data

Plain Bytes => Encrypted Base64UrlSafe

let plainBytes = [0xde, 0xad, 0xbe, 0xef];
let encBase64UrlSafe = cipher.encrypt(plainBytes);
console.info("Encrypted (URL-Safe Base64)", encBase64UrlSafe);

Plain String => Encrypted Base64UrlSafe

let plainText = "123-45-6789";
let encBase64UrlSafe = cipher.encryptString(plainText);
console.info("Encrypted (URL-Safe Base64)", encBase64UrlSafe);

Plain Bytes => Encrypted Bytes

let plainBytes = [0xde, 0xad, 0xbe, 0xef];
let encBytes = cipher.encryptAsBytes(plainBytes);
console.info("Encrypted (Bytes)", encBytes);

Plain String => Encrypted Bytes

let plainText = "123-45-6789";
let encBytes = cipher.encryptStringAsBytes(plainText);
console.info("Encrypted (Bytes)", encBytes);

4. Decrypt (Decipher) Data

Encrypted String => Plain Bytes

let bytes = cipher.decrypt(encBase64UrlSafe);
console.info("Plain (Bytes)", bytes);

Encrypted Bytes => Plain Bytes

let bytes = cipher.decryptBytes(encBytes);
console.info("Plain (Bytes)", bytes);

Encrypted String => Plain String

let text = cipher.decryptToString(encBase64UrlSafe);
console.info("Plain (Text)", text);

Encrypted Bytes => Plain String

let text = cipher.decryptBytesToString(encBytes);
console.info("Plain (Text)", text);

5. Convert between Bytes, Hex, Base64, and URL-Safe Base64

Doing what Uint8Array should do, but doesn't.

Bytes <=> Hex

let hex = Cipher.utils.bytesToHex(bytes);
let bytes = Cipher.utils.hexToBytes(hex);

Bytes <=> Base64

let base64 = Cipher.utils.bytesToBase64(bytes);
let bytes = Cipher.utils.base64ToBytes(base64);

Bytes <=> URL-Safe Base64

let base64urlsafe = Cipher.utils.bytesToUrlSafe(bytes);
let bytes = Cipher.utils.urlSafeToBytes(base64urlsafe);

API

Cipher.create(keyBytes)                => cipher instance

cipher.encrypt(bytes)                  => Promise<Base64UrlSafe>
cipher.encryptString(string)           => Promise<Base64UrlSafe>

cipher.encryptAsBytes(bytes)           => Promise<Uint8Array>
cipher.encryptStringAsBytes(string)    => Promise<Uint8Array>

cipher.decrypt(encrypted)              => Promise<Uint8Array>
cipher.decryptToString(encrypted)      => Promise<Base64UrlSafe>

cipher.decryptBytes(encBytes)          => Promise<Uint8Array>
cipher.decryptBytesToString(encBytes)  => Promise<Base64UrlSafe>
Cipher.utils.bytesToHex(bytes)         => hex string
Cipher.utils.hexToBytes(hex)           => bytes

Cipher.utils.bytesToBase64(bytes)      => base64
Cipher.utils.base64ToBytes(base64)     => bytes

Cipher.utils.bytesToUrlSafe(bytes)     => url-safe base64 string
Cipher.utils.urlSafeToBytes(url64)     => bytes

Implementation Details

The Initialization Vector (IV) is a salt that prevents known-plaintext attacks - meaning that if you encrypt the same message with the same key twice, you get a different encrypted output.

The first 12-bytes (96-bits) are for the IV. The following bytes are the data and the Tag.

If the data is somehow corrupted or truncated, but the first bytes are intact, it may be possible to use the IV to restore some of the partial data (though Tag verification will likely fail).

LICENSE

Copyright 2021-Present Root, Inc

This Source Code Form is subject to the terms of the Mozilla
Public License, v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at
https://mozilla.org/MPL/2.0/.