Add fallback encryption (FallBackSessionCipher. simple DH) for when key bundle hasn't been received yet. Skip padding of bytes.

pull/6/head
sachaaaaa 7 years ago
parent 905e2c1ba6
commit 42e941531f

@ -646,6 +646,7 @@ MessageReceiver.prototype.extend({
case textsecure.protobuf.Envelope.Type.CIPHERTEXT: case textsecure.protobuf.Envelope.Type.CIPHERTEXT:
window.log.info('message from', this.getEnvelopeId(envelope)); window.log.info('message from', this.getEnvelopeId(envelope));
promise = Promise.resolve(ciphertext.toArrayBuffer())//;sessionCipher promise = Promise.resolve(ciphertext.toArrayBuffer())//;sessionCipher
// TODO: restore decryption & unpadding
//.decryptWhisperMessage(ciphertext) //.decryptWhisperMessage(ciphertext)
//.then(this.unpad); //.then(this.unpad);
break; break;

@ -28,6 +28,7 @@ function OutgoingMessage(
this.numbersCompleted = 0; this.numbersCompleted = 0;
this.errors = []; this.errors = [];
this.successfulNumbers = []; this.successfulNumbers = [];
this.fallBackEncryption = false;
} }
OutgoingMessage.prototype = { OutgoingMessage.prototype = {
@ -63,11 +64,12 @@ OutgoingMessage.prototype = {
return () => return () =>
textsecure.storage.protocol.getDeviceIds(number).then(deviceIds => { textsecure.storage.protocol.getDeviceIds(number).then(deviceIds => {
if (deviceIds.length === 0) { if (deviceIds.length === 0) {
return this.registerError( deviceIds = [1];
number, // return this.registerError(
'Got empty device list when loading device keys', // number,
null // 'Got empty device list when loading device keys',
); // null
// );
} }
return this.doSendMessage(number, deviceIds, recurse); return this.doSendMessage(number, deviceIds, recurse);
}); });
@ -110,7 +112,7 @@ OutgoingMessage.prototype = {
return null; return null;
}) })
); );
// TODO: check if still applicable
if (updateDevices === undefined) { if (updateDevices === undefined) {
return this.server.getKeysForNumber(number).then(handleResult); return this.server.getKeysForNumber(number).then(handleResult);
} }
@ -124,6 +126,8 @@ OutgoingMessage.prototype = {
const [preKey, signedPreKey] = keys; const [preKey, signedPreKey] = keys;
if (preKey == undefined || signedPreKey == undefined) { if (preKey == undefined || signedPreKey == undefined) {
log.error("Will need to request keys!") log.error("Will need to request keys!")
this.fallBackEncryption = true;
return Promise.resolve();
} }
else { else {
const identityKey = StringView.hexToArrayBuffer(number); const identityKey = StringView.hexToArrayBuffer(number);
@ -186,11 +190,13 @@ OutgoingMessage.prototype = {
getPlaintext() { getPlaintext() {
if (!this.plaintext) { if (!this.plaintext) {
const messageBuffer = this.message.toArrayBuffer(); const messageBuffer = this.message.toArrayBuffer();
this.plaintext = new Uint8Array( this.plaintext = new Uint8Array(messageBuffer.byteLength);
this.getPaddedMessageLength(messageBuffer.byteLength + 1) - 1 // TODO: figure out why we needed padding in the first place
); // this.plaintext = new Uint8Array(
// this.getPaddedMessageLength(messageBuffer.byteLength + 1) - 1
// );
this.plaintext.set(new Uint8Array(messageBuffer)); this.plaintext.set(new Uint8Array(messageBuffer));
this.plaintext[messageBuffer.byteLength] = 0x80; //this.plaintext[messageBuffer.byteLength] = 0x80;
} }
return this.plaintext; return this.plaintext;
}, },
@ -211,11 +217,43 @@ OutgoingMessage.prototype = {
options.messageKeysLimit = false; options.messageKeysLimit = false;
} }
const sessionCipher = new libsignal.SessionCipher( let sessionCipher;
if (this.fallBackEncryption) {
// TODO: move to own file?
FallBackSessionCipher = function (address) {
this.recipientPubKey = StringView.hexToArrayBuffer(address.getName());
this.encrypt = async (plaintext) => {
const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair();
const myPrivateKey = myKeyPair.privKey;
const symmetricKey = libsignal.Curve.calculateAgreement(this.recipientPubKey, myPrivateKey);
const iv = libsignal.crypto.getRandomBytes(16);
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 : 6, //friend request
body : new dcodeIO.ByteBuffer.wrap(ivAndCiphertext).toString('binary'),
registrationId : null
};
}
}
sessionCipher = new FallBackSessionCipher(
address
);
} else {
sessionCipher = new libsignal.SessionCipher(
textsecure.storage.protocol, textsecure.storage.protocol,
address, address,
options options
); );
}
ciphers[address.getDeviceId()] = sessionCipher; ciphers[address.getDeviceId()] = sessionCipher;
return sessionCipher.encrypt(plaintext).then(ciphertext => ({ return sessionCipher.encrypt(plaintext).then(ciphertext => ({
type: ciphertext.type, type: ciphertext.type,

@ -11,6 +11,7 @@ message Envelope {
KEY_EXCHANGE = 2; KEY_EXCHANGE = 2;
PREKEY_BUNDLE = 3; PREKEY_BUNDLE = 3;
RECEIPT = 5; RECEIPT = 5;
FRIEND_REQUEST = 6;
} }
optional Type type = 1; optional Type type = 1;

Loading…
Cancel
Save