UNPKG

ilp-protocol-stream

Version:

Interledger Transport Protocol for sending multiple streams of money and data over ILP.

112 lines 4.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.decryptConnectionAddressToken = exports.encryptConnectionAddressToken = exports.generateReceiptHMAC = exports.generateSharedSecretFromToken = exports.randomBytes = exports.hmac = exports.decrypt = exports.encrypt = exports.hash = void 0; const { crypto } = self; const HASH_ALGORITHM = 'SHA-256'; const ENCRYPTION_ALGORITHM = 'AES-GCM'; const IV_LENGTH = 12; const AUTH_TAG_BYTES = 16; const AUTH_TAG_BITS = 8 * AUTH_TAG_BYTES; const CACHE_EXPIRY = 30000; class KeyCache { constructor() { this.cache = new Map(); } cleanup() { const now = Date.now(); for (const [cacheData, cacheEntry] of this.cache) { if (now - cacheEntry.accessTime > CACHE_EXPIRY) { this.cache.delete(cacheData); } } } async importKey(keyData, algorithm, keyUsages) { const oldEntry = this.cache.get(keyData); if (oldEntry) { oldEntry.accessTime = Date.now(); return oldEntry.keyObject; } const keyObject = await crypto.subtle.importKey('raw', keyData, algorithm, false, keyUsages); this.cache.set(keyData, { keyObject, accessTime: Date.now(), }); return keyObject; } } const hmacKeyCache = new KeyCache(); const aesKeyCache = new KeyCache(); setInterval(() => { hmacKeyCache.cleanup(); aesKeyCache.cleanup(); }, 30000); async function hash(preimage) { const digest = await crypto.subtle.digest({ name: HASH_ALGORITHM }, preimage); return Buffer.from(digest); } exports.hash = hash; async function encrypt(pskEncryptionKey, ...buffers) { const iv = randomBytes(IV_LENGTH); const key = await aesKeyCache.importKey(pskEncryptionKey, ENCRYPTION_ALGORITHM, [ 'encrypt', 'decrypt', ]); const ciphertext = await crypto.subtle.encrypt({ name: ENCRYPTION_ALGORITHM, iv, tagLength: AUTH_TAG_BITS, }, key, Buffer.concat(buffers)); const tagStart = ciphertext.byteLength - AUTH_TAG_BYTES; const tag = ciphertext.slice(tagStart); const data = ciphertext.slice(0, tagStart); return Buffer.concat([Buffer.from(iv), Buffer.from(tag), Buffer.from(data)]); } exports.encrypt = encrypt; async function decrypt(pskEncryptionKey, data) { const nonce = data.slice(0, IV_LENGTH); const tag = data.slice(IV_LENGTH, IV_LENGTH + AUTH_TAG_BYTES); const cipherdata = data.slice(IV_LENGTH + AUTH_TAG_BYTES); const key = await aesKeyCache.importKey(pskEncryptionKey, ENCRYPTION_ALGORITHM, [ 'encrypt', 'decrypt', ]); const decryptedData = await crypto.subtle.decrypt({ name: ENCRYPTION_ALGORITHM, iv: nonce, }, key, Buffer.concat([cipherdata, tag])); return Buffer.from(decryptedData); } exports.decrypt = decrypt; const HMAC_ALGORITHM = { name: 'HMAC', hash: { name: HASH_ALGORITHM }, }; async function hmac(key, message) { const hmacKey = await hmacKeyCache.importKey(key, HMAC_ALGORITHM, ['sign', 'verify']); const signature = await crypto.subtle.sign('HMAC', hmacKey, message); return Buffer.from(signature); } exports.hmac = hmac; function randomBytes(size) { const randArray = new Uint8Array(size); const randValues = crypto.getRandomValues(randArray); return Buffer.from(randValues); } exports.randomBytes = randomBytes; function generateSharedSecretFromToken(_seed, _token) { throw new Error('unreachable in browser'); } exports.generateSharedSecretFromToken = generateSharedSecretFromToken; function generateReceiptHMAC(_secret, _message) { throw new Error('unreachable in browser'); } exports.generateReceiptHMAC = generateReceiptHMAC; function encryptConnectionAddressToken(_seed, _token) { throw new Error('unreachable in browser'); } exports.encryptConnectionAddressToken = encryptConnectionAddressToken; function decryptConnectionAddressToken(_seed, _token) { throw new Error('unreachable in browser'); } exports.decryptConnectionAddressToken = decryptConnectionAddressToken; //# sourceMappingURL=crypto-browser.js.map