open-collaboration-protocol
Version:
Open Collaboration Protocol implementation, part of the Open Collaboration Tools project
103 lines • 4.38 kB
JavaScript
// ******************************************************************************
// Copyright 2024 TypeFox GmbH
// This program and the accompanying materials are made available under the
// terms of the MIT License, which is available in the project root.
// ******************************************************************************
import { Encoding } from './encoding.js';
import { Compression } from './compression.js';
import { getCryptoLib } from '../utils/crypto.js';
import { fromBase64, toBase64 } from '../utils/base64.js';
export var Encryption;
(function (Encryption) {
async function generateKeyPair() {
return getCryptoLib().generateKeyPair();
}
Encryption.generateKeyPair = generateKeyPair;
async function generateSymKey() {
return getCryptoLib().generateSymKey();
}
Encryption.generateSymKey = generateSymKey;
async function symEncrypt(data, key, iv) {
return getCryptoLib().symEncrypt(data, key, iv);
}
Encryption.symEncrypt = symEncrypt;
async function symDecrypt(data, key, iv) {
return getCryptoLib().symDecrypt(data, key, iv);
}
Encryption.symDecrypt = symDecrypt;
async function publicEncrypt(data, key) {
return getCryptoLib().publicEncrypt(data, key);
}
Encryption.publicEncrypt = publicEncrypt;
async function privateDecrypt(data, key) {
return getCryptoLib().privateDecrypt(data, key);
}
Encryption.privateDecrypt = privateDecrypt;
async function generateIV() {
return getCryptoLib().generateIV();
}
Encryption.generateIV = generateIV;
async function encrypt(message, symKey, ...keys) {
const key = await symKey.symmetricKey;
const keyBuffer = fromBase64(key);
const content = message.content;
const encoded = Encoding.encode(content);
const compressionAlgo = Compression.bestFit(keys.map(key => key.supportedCompression));
const compressed = await Compression.compress(encoded, compressionAlgo);
const iv = await getCryptoLib().generateIV();
const encrypted = await getCryptoLib().symEncrypt(compressed, key, iv);
const encryptedKeys = await Promise.all(keys.map(async (key) => {
let cachedKey = symKey.cache?.[key.peerId];
if (!cachedKey) {
cachedKey = toBase64(await getCryptoLib().publicEncrypt(keyBuffer, key.publicKey));
if (symKey.cache) {
symKey.cache[key.peerId] = cachedKey;
}
}
return {
target: key.peerId,
key: cachedKey,
iv
};
}));
return {
...message,
metadata: {
...message.metadata,
encryption: {
keys: encryptedKeys
},
compression: {
algorithm: compressionAlgo
}
},
content: encrypted
};
}
Encryption.encrypt = encrypt;
async function decrypt(message, privateKey) {
// We always expect exactly one key for every message we receive
// This is obviously the case for any 1:1 message such as requests or notifications.
// However, even for broadcasts, the server will modify the message to only contain the key for the target peer.
if (message.metadata.encryption.keys.length !== 1) {
throw new Error('Expected exactly one key for decryption');
}
const key = message.metadata.encryption.keys[0];
let decryptedKey = privateKey.cache?.[key.key];
if (!decryptedKey) {
decryptedKey = toBase64(await getCryptoLib().privateDecrypt(fromBase64(key.key), privateKey.privateKey));
if (privateKey.cache) {
privateKey.cache[key.key] = decryptedKey;
}
}
const decrypted = await getCryptoLib().symDecrypt(message.content, decryptedKey, key.iv);
const decompressed = await Compression.decompress(decrypted, message.metadata.compression.algorithm);
const decoded = Encoding.decode(decompressed);
return {
...message,
content: decoded
};
}
Encryption.decrypt = decrypt;
})(Encryption || (Encryption = {}));
//# sourceMappingURL=encryption.js.map