UNPKG

@jsxc/jsxc

Version:

Real-time XMPP chat application with video calls, file transfer and encrypted communication

73 lines (58 loc) 2.19 kB
import ArrayBufferUtils from '../util/ArrayBuffer'; import { AES_TAG_LENGTH, AES_KEY_LENGTH, AES_EXTRACTABLE } from '../util/Const'; const ALGO_NAME = 'AES-GCM'; export async function decrypt(exportedAESKey: ArrayBuffer, iv: Uint8Array, data: ArrayBuffer): Promise<string> { let key = await window.crypto.subtle.importKey('raw', exportedAESKey, ALGO_NAME, false, ['decrypt']); let decryptedBuffer = await window.crypto.subtle.decrypt( { name: ALGO_NAME, iv, tagLength: AES_TAG_LENGTH, }, key, data ); return ArrayBufferUtils.decode(decryptedBuffer); } export async function encrypt(plaintext): Promise<{ keydata: ArrayBuffer; iv: BufferSource; payload: ArrayBuffer }> { let iv = window.crypto.getRandomValues(new Uint8Array(12)); let key = await generateAESKey(); let encrypted = await generateAESencryptedMessage(iv, key, plaintext); let ciphertext = encrypted.ciphertext; let authenticationTag = encrypted.authenticationTag; let keydata = await window.crypto.subtle.exportKey('raw', <CryptoKey>key); return { keydata: ArrayBufferUtils.concat(keydata, <ArrayBuffer>authenticationTag), iv, payload: ciphertext, }; } async function generateAESKey(): Promise<CryptoKey | CryptoKeyPair> { let algo = { name: ALGO_NAME, length: AES_KEY_LENGTH, }; let keyUsage: KeyUsage[] = ['encrypt', 'decrypt']; let key = await window.crypto.subtle.generateKey(algo, AES_EXTRACTABLE, keyUsage); return key; } async function generateAESencryptedMessage( iv, key, plaintext ): Promise<{ ciphertext: ArrayBuffer; authenticationTag: ArrayBuffer }> { let encryptOptions = { name: ALGO_NAME, iv, tagLength: AES_TAG_LENGTH, }; let encodedPlaintext = ArrayBufferUtils.encode(plaintext); let encrypted = await window.crypto.subtle.encrypt(encryptOptions, key, encodedPlaintext); let ciphertextLength = encrypted.byteLength - ((128 + 7) >> 3); let ciphertext = encrypted.slice(0, ciphertextLength); let authenticationTag = encrypted.slice(ciphertextLength); return { ciphertext, authenticationTag, }; }