UNPKG

open-collaboration-protocol

Version:

Open Collaboration Protocol implementation, part of the Open Collaboration Tools project

117 lines (109 loc) 4.57 kB
// ****************************************************************************** // 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 { fromBase64, toBase64 } from './base64.js'; export interface KeyPair { publicKey: string; privateKey: string; } export interface CryptoLib { /** * Encrypts the given data with the given key. */ symEncrypt(data: Uint8Array, key: string, iv: string): Promise<Uint8Array>; /** * Decrypts the given data with the given key. */ symDecrypt(data: Uint8Array, key: string, iv: string): Promise<Uint8Array>; generateSymKey(): Promise<string>; generateIV(): Promise<string>; publicEncrypt(data: Uint8Array, key: string): Promise<Uint8Array>; privateDecrypt(data: Uint8Array, key: string): Promise<Uint8Array>; /** * Generates a random key pair. */ generateKeyPair(): Promise<KeyPair>; } export type CryptoModule = typeof self.crypto | typeof import('node:crypto').webcrypto; let cryptoModule: CryptoModule | undefined; export const setCryptoModule = (cm: CryptoModule): void => { cryptoModule = cm; }; export const getCryptoLib = (): CryptoLib => { if (cryptoModule === undefined) { throw new Error('Crypto module is not available. Please call the initializeProtocol() function first.'); } const subtle = cryptoModule.subtle; return { async generateKeyPair() { const pair = await subtle.generateKey({ name: 'RSA-OAEP', modulusLength: 4096, publicExponent: new Uint8Array([1, 0, 1]), hash: 'SHA-256' }, true, ['encrypt', 'decrypt']); const exportedPublic = await subtle.exportKey('spki', pair.publicKey); const exportedPrivate = await subtle.exportKey('pkcs8', pair.privateKey); return { privateKey: toBase64(new Uint8Array(exportedPrivate)), publicKey: toBase64(new Uint8Array(exportedPublic)) }; }, async generateSymKey() { const key = await subtle.generateKey({ name: 'AES-CBC', length: 256 }, true, ['encrypt', 'decrypt']); const exportedKey = await subtle.exportKey('raw', key); return toBase64(new Uint8Array(exportedKey)); }, async generateIV() { const iv = (crypto.getRandomValues<Uint8Array>)(new Uint8Array(16)); return toBase64(iv); }, async symEncrypt(data: Uint8Array, key: string, iv: string) { const cryptoKey = await subtle.importKey('raw', fromBase64(key), 'AES-CBC', false, ['encrypt']); const arrayBuffer = await subtle.encrypt({ name: 'AES-CBC', iv: fromBase64(iv), }, cryptoKey, data); return new Uint8Array(arrayBuffer); }, async symDecrypt(data: Uint8Array, key: string, iv: string) { const cryptoKey = await subtle.importKey('raw', fromBase64(key), 'AES-CBC', false, ['decrypt']); const arrayBuffer = await subtle.decrypt({ name: 'AES-CBC', iv: fromBase64(iv), }, cryptoKey, data); return new Uint8Array(arrayBuffer); }, async publicEncrypt(data: Uint8Array, key: string) { const publicKey = await subtle.importKey( 'spki', fromBase64(key), { name: 'RSA-OAEP', hash: 'SHA-256' }, false, ['encrypt'] ); const encrypted = await subtle.encrypt({ name: 'RSA-OAEP' }, publicKey, data); return new Uint8Array(encrypted); }, async privateDecrypt(data: Uint8Array, key: string) { const privateKey = await subtle.importKey( 'pkcs8', fromBase64(key), { name: 'RSA-OAEP', hash: 'SHA-256' }, true, ['decrypt'] ); const decrypted = await subtle.decrypt({ name: 'RSA-OAEP' }, privateKey, data); return new Uint8Array(decrypted); } }; };