|
|
|
@ -1,15 +1,18 @@
|
|
|
|
|
/* global dcodeIO, Internal */
|
|
|
|
|
/* global dcodeIO, Internal, libsignal, sodium */
|
|
|
|
|
/* eslint-disable no-console */
|
|
|
|
|
/* eslint-disable strict */
|
|
|
|
|
|
|
|
|
|
const functions = {
|
|
|
|
|
arrayBufferToStringBase64,
|
|
|
|
|
fromBase64ToArrayBuffer,
|
|
|
|
|
fromHexToArrayBuffer,
|
|
|
|
|
verifySignature,
|
|
|
|
|
DecryptAESGCM,
|
|
|
|
|
deriveSymmetricKey,
|
|
|
|
|
encryptForPubkey,
|
|
|
|
|
generateEphemeralKeyPair,
|
|
|
|
|
decryptAttachmentBuffer,
|
|
|
|
|
encryptAttachmentBuffer,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onmessage = async e => {
|
|
|
|
@ -196,3 +199,65 @@ async function DecryptAESGCM(symmetricKey, ivAndCiphertext) {
|
|
|
|
|
|
|
|
|
|
return crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce }, key, ciphertext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getSodium() {
|
|
|
|
|
await sodium.ready;
|
|
|
|
|
return sodium;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Uint8Array, ArrayBuffer
|
|
|
|
|
async function decryptAttachmentBuffer(encryptingKey, bufferIn) {
|
|
|
|
|
const sodium = await getSodium();
|
|
|
|
|
|
|
|
|
|
const header = new Uint8Array(
|
|
|
|
|
bufferIn.slice(0, sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const encryptedBuffer = new Uint8Array(
|
|
|
|
|
bufferIn.slice(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES)
|
|
|
|
|
);
|
|
|
|
|
try {
|
|
|
|
|
/* Decrypt the stream: initializes the state, using the key and a header */
|
|
|
|
|
const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, encryptingKey);
|
|
|
|
|
// what if ^ this call fail (? try to load as a unencrypted attachment?)
|
|
|
|
|
|
|
|
|
|
const messageTag = sodium.crypto_secretstream_xchacha20poly1305_pull(state, encryptedBuffer);
|
|
|
|
|
// we expect the final tag to be there. If not, we might have an issue with this file
|
|
|
|
|
// maybe not encrypted locally?
|
|
|
|
|
if (messageTag.tag === sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
|
|
|
|
|
return messageTag.message;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('Failed to load the file as an encrypted one', e);
|
|
|
|
|
}
|
|
|
|
|
return new Uint8Array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Uint8Array, ArrayBuffer
|
|
|
|
|
async function encryptAttachmentBuffer(encryptingKey, bufferIn) {
|
|
|
|
|
const sodium = await getSodium();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const uintArrayIn = new Uint8Array(bufferIn);
|
|
|
|
|
|
|
|
|
|
/* Set up a new stream: initialize the state and create the header */
|
|
|
|
|
const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push(encryptingKey);
|
|
|
|
|
/* Now, encrypt the buffer. */
|
|
|
|
|
const bufferOut = sodium.crypto_secretstream_xchacha20poly1305_push(
|
|
|
|
|
state,
|
|
|
|
|
uintArrayIn,
|
|
|
|
|
null,
|
|
|
|
|
sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const encryptedBufferWithHeader = new Uint8Array(bufferOut.length + header.length);
|
|
|
|
|
encryptedBufferWithHeader.set(header);
|
|
|
|
|
encryptedBufferWithHeader.set(bufferOut, header.length);
|
|
|
|
|
|
|
|
|
|
return { encryptedBufferWithHeader, header };
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('encryptAttachmentBuffer error: ', e);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|