ilp-protocol-stream
Version:
Interledger Transport Protocol for sending multiple streams of money and data over ILP.
112 lines • 4.16 kB
JavaScript
;
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