Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion email_composer/src/containers/Composer.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class ComposerWrapper extends Component {
: Status.DISABLED;
state = { ...composerData, status };
}
const { key, iv } = generateKeyAndIv(null, 8, null);
const { key, iv } = generateKeyAndIv(null, 8);
state = { ...state, key, iv };
fileManager.on(FILE_PROGRESS, this.handleUploadProgress);
fileManager.on(FILE_FINISH, this.handleUploadSuccess);
Expand Down
43 changes: 31 additions & 12 deletions email_composer/src/libs/signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import {
import SignalProtocolStore from './store';
import { CustomError } from './../utils/CustomError';
import {
AesEncryptToBase64,
AesEncrypt,
generateKeyAndIv,
base64ToWordArray
base64ToWordArray,
wordArrayToByteArray,
wordArrayToBase64,
byteArrayToWordArray
} from '../utils/AESUtils';

const KeyHelper = libsignal.KeyHelper;
Expand Down Expand Up @@ -199,6 +202,7 @@ const encryptPostEmail = async ({
peer,
fileKeyParams
);
const fileKey = criptextEmails[0] ? criptextEmails[0].fileKey : null;

const allExternalRecipients = [
...externalRecipients.to,
Expand All @@ -207,7 +211,7 @@ const encryptPostEmail = async ({
];
const hasExternalRecipients = allExternalRecipients.length > 0;
const { session, encryptedBody } = externalEmailPassword.length
? await encryptExternalEmail(body, externalEmailPassword)
? await encryptExternalEmail(body, externalEmailPassword, fileKey)
: { session: null, encryptedBody: null };

const guestEmail = hasExternalRecipients
Expand Down Expand Up @@ -235,7 +239,7 @@ const encryptPostEmail = async ({
return res;
};

const createDummyKeyBundle = async () => {
const createDummyKeyBundle = async fileKey => {
const preKeyId = 1;
const signedPreKeyId = 1;
const { identityKey, registrationId } = await generateIdentity();
Expand All @@ -252,6 +256,7 @@ const createDummyKeyBundle = async () => {
signedPreKey
};
const dummySession = {
fileKey,
identityKey: {
publicKey: util.toBase64(identityKey.pubKey),
privateKey: util.toBase64(identityKey.privKey)
Expand Down Expand Up @@ -295,10 +300,10 @@ const generatePreKeyBundle = async ({
return { preKey, signedPreKey };
};

const encryptExternalEmail = async (body, password) => {
const encryptExternalEmail = async (body, password, fileKey) => {
const recipient = password;
const deviceId = 1;
const { dummySession, sessionParams } = await createDummyKeyBundle();
const { dummySession, sessionParams } = await createDummyKeyBundle(fileKey);
const keys = {
preKey: {
id: sessionParams.preKey.keyId,
Expand All @@ -319,12 +324,26 @@ const encryptExternalEmail = async (body, password) => {
);

const saltLength = 8;
const keyLength = 128 / 32;
const { key, iv } = generateKeyAndIv(password, saltLength, keyLength);
const keyArray = base64ToWordArray(key);
const ivArray = base64ToWordArray(iv);
const sessionString = JSON.stringify(dummySession);
const session = AesEncryptToBase64(sessionString, keyArray, ivArray);
const { key, iv, salt } = generateKeyAndIv(password, saltLength);
const saltWArray = base64ToWordArray(salt);
const ivWArray = base64ToWordArray(iv);
const keyWArray = base64ToWordArray(key);

const dummySessionString = JSON.stringify(dummySession);
const encryptedSessionWArray = AesEncrypt(
dummySessionString,
keyWArray,
ivWArray
);
const saltBArray = wordArrayToByteArray(saltWArray);
const ivBArray = wordArrayToByteArray(ivWArray);
const encryptedSessionBArray = wordArrayToByteArray(encryptedSessionWArray);
const sessionByteArray = saltBArray.concat(
ivBArray.concat(encryptedSessionBArray)
);

const sessionWordArray = byteArrayToWordArray(sessionByteArray);
const session = wordArrayToBase64(sessionWordArray);
return {
session,
encryptedBody: encryptedBody.body
Expand Down
65 changes: 55 additions & 10 deletions email_composer/src/utils/AESUtils.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,71 @@
import CryptoJS from 'crypto-js';

export const generateKeyAndIv = (phrase, saltsize, keysize) => {
export const generateKeyAndIv = (phrase, saltsize) => {
const passphrase = phrase || CryptoJS.lib.WordArray.random(saltsize);
const keySalt = CryptoJS.lib.WordArray.random(saltsize);
const ivSalt = CryptoJS.lib.WordArray.random(saltsize);
const salt = CryptoJS.lib.WordArray.random(saltsize);
const keyParams = {
keySize: keysize || 128 / 32,
iterations: 1000
keySize: 128 / 32,
iterations: 10000,
hasher: CryptoJS.algo.SHA256
};
const keyArray = CryptoJS.PBKDF2(passphrase, keySalt, keyParams);
const ivArray = CryptoJS.PBKDF2(passphrase, ivSalt, keyParams);
const keyArray = CryptoJS.PBKDF2(passphrase, salt, keyParams);
const ivArray = CryptoJS.lib.WordArray.random(16);
return {
key: keyArray.toString(CryptoJS.enc.Base64),
iv: ivArray.toString(CryptoJS.enc.Base64)
iv: ivArray.toString(CryptoJS.enc.Base64),
salt: salt.toString(CryptoJS.enc.Base64)
};
};

export const AesEncryptToBase64 = (data, keyArray, ivArray) => {
export const AesEncrypt = (data, keyArray, ivArray) => {
const encrypted = CryptoJS.AES.encrypt(data, keyArray, { iv: ivArray });
return encrypted.toString();
const based64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
return base64ToWordArray(based64);
};

export const base64ToWordArray = base64String => {
return CryptoJS.enc.Base64.parse(base64String);
};

export const wordArrayToBase64 = wordArray => {
return CryptoJS.enc.Base64.stringify(wordArray);
};

export const byteArrayToWordArray = bytearray => {
const wa = [];
let i;
for (i = 0; i < bytearray.length; i++) {
wa[(i / 4) | 0] |= bytearray[i] << (24 - 8 * i);
}
return CryptoJS.lib.WordArray.create(wa, bytearray.length);
};

const wordToByteArray = (word, length) => {
const ba = [];
const xFF = 0xff;
if (length > 0) ba.push(word >>> 24);
if (length > 1) ba.push((word >>> 16) & xFF);
if (length > 2) ba.push((word >>> 8) & xFF);
if (length > 3) ba.push(word & xFF);
return ba;
};

export const wordArrayToByteArray = (wordarray, length) => {
if (
wordarray.hasOwnProperty('sigBytes') &&
wordarray.hasOwnProperty('words')
) {
length = wordarray.sigBytes;
wordarray = wordarray.words;
}
const result = [];
let i = 0;
let bytes;
while (length > 0) {
bytes = wordToByteArray(wordarray[i], Math.min(4, length));
length -= bytes.length;
result.push(bytes);
i++;
}
return [].concat.apply([], result);
};