/* global window, libsignal, textsecure, StringView */ // eslint-disable-next-line func-names (function() { window.libloki = window.libloki || {}; class FallBackDecryptionError extends Error {} const IV_LENGTH = 16; class FallBackSessionCipher { constructor(address) { this.identityKeyString = address.getName(); this.pubKey = StringView.hexToArrayBuffer(address.getName()); } async encrypt(plaintext) { const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair(); const myPrivateKey = myKeyPair.privKey; const symmetricKey = libsignal.Curve.calculateAgreement( this.pubKey, myPrivateKey ); const iv = libsignal.crypto.getRandomBytes(IV_LENGTH); const ciphertext = await libsignal.crypto.encrypt( symmetricKey, plaintext, iv ); const ivAndCiphertext = new Uint8Array( iv.byteLength + ciphertext.byteLength ); ivAndCiphertext.set(new Uint8Array(iv)); ivAndCiphertext.set(new Uint8Array(ciphertext), iv.byteLength); return { type: textsecure.protobuf.Envelope.Type.FRIEND_REQUEST, body: ivAndCiphertext, registrationId: null, }; } async decrypt(ivAndCiphertext) { const iv = ivAndCiphertext.slice(0, IV_LENGTH); const cipherText = ivAndCiphertext.slice(IV_LENGTH); const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair(); const myPrivateKey = myKeyPair.privKey; const symmetricKey = libsignal.Curve.calculateAgreement( this.pubKey, myPrivateKey ); try { return await libsignal.crypto.decrypt(symmetricKey, cipherText, iv); } catch (e) { throw new FallBackDecryptionError( `Could not decrypt message from ${ this.identityKeyString } using FallBack encryption.` ); } } } window.libloki.crypto = { FallBackSessionCipher, FallBackDecryptionError, }; })();