@bitblit/ratchet-common
Version:
Common tools for general use
56 lines • 2.57 kB
JavaScript
import { RequireRatchet } from "./require-ratchet.js";
import { NumberRatchet } from "./number-ratchet.js";
import { Base64Ratchet } from "./base64-ratchet.js";
export class SimpleEncryptionRatchet {
urlSafe;
ivLength;
sharedKey;
constructor(sharedRawKey, urlSafe = false, ivLength = 12) {
this.urlSafe = urlSafe;
this.ivLength = ivLength;
RequireRatchet.notNullOrUndefined(sharedRawKey);
RequireRatchet.true(ivLength >= 12, 'ivLength must be at least 12');
this.sharedKey = this.createSharedKey(sharedRawKey);
}
strToBuf(str) {
return new TextEncoder().encode(str);
}
bufToBase64(buf) {
return btoa(String.fromCharCode(...new Uint8Array(buf)));
}
base64ToBuf(base64) {
return new Uint8Array(atob(base64).split('').map(c => c.charCodeAt(0)));
}
async encrypt(data) {
const iv = crypto.getRandomValues(new Uint8Array(this.ivLength));
const encoded = this.strToBuf(data);
const key = await this.sharedKey;
const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, encoded);
const ivMsg = this.bufToBase64(iv.buffer);
const dataMsg = this.bufToBase64(ciphertext);
let rval = ivMsg.length + 'K' + ivMsg + dataMsg;
if (this.urlSafe) {
rval = Base64Ratchet.encodeStringToBase64UrlString(rval);
}
return rval;
}
async decrypt(encryptedValueIn) {
const encryptedValue = this.urlSafe ? Base64Ratchet.decodeBase64UrlStringToString(encryptedValueIn) : encryptedValueIn;
const split = encryptedValue?.indexOf('K');
if (!split || split < 1) {
throw new Error('Invalid split : ' + split);
}
const ivLen = NumberRatchet.safeNumber(encryptedValue.substring(0, split));
const iv = encryptedValue.substring(split + 1, split + 1 + ivLen);
const data = encryptedValue.substring(split + 1 + ivLen);
const key = await this.sharedKey;
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: this.base64ToBuf(iv) }, key, this.base64ToBuf(data));
return new TextDecoder().decode(decrypted);
}
async createSharedKey(rawKeyIn) {
const rawKey = typeof rawKeyIn === 'string' ? rawKeyIn : await rawKeyIn;
const keyMaterial = this.strToBuf(rawKey.padEnd(32, '0').slice(0, 32));
return crypto.subtle.importKey("raw", keyMaterial, "AES-GCM", false, ["encrypt", "decrypt"]);
}
}
//# sourceMappingURL=simple-encryption-ratchet.js.map