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:
window.log.info('message from', this.getEnvelopeId(envelope));
promise = Promise.resolve(ciphertext.toArrayBuffer())//;sessionCipher
// TODO: restore decryption & unpadding
//.decryptWhisperMessage(ciphertext)
//.then(this.unpad);
break;

@ -28,6 +28,7 @@ function OutgoingMessage(
this.numbersCompleted = 0;
this.errors = [];
this.successfulNumbers = [];
this.fallBackEncryption = false;
}
OutgoingMessage.prototype = {
@ -63,11 +64,12 @@ OutgoingMessage.prototype = {
return () =>
textsecure.storage.protocol.getDeviceIds(number).then(deviceIds => {
if (deviceIds.length === 0) {
return this.registerError(
number,
'Got empty device list when loading device keys',
null
);
deviceIds = [1];
// return this.registerError(
// number,
// 'Got empty device list when loading device keys',
// null
// );
}
return this.doSendMessage(number, deviceIds, recurse);
});
@ -110,7 +112,7 @@ OutgoingMessage.prototype = {
return null;
})
);
// TODO: check if still applicable
if (updateDevices === undefined) {
return this.server.getKeysForNumber(number).then(handleResult);
}
@ -121,15 +123,17 @@ OutgoingMessage.prototype = {
textsecure.storage.protocol.loadContactPreKey(number),
textsecure.storage.protocol.loadContactSignedPreKey(number)
]).then((keys) => {
const [preKey, signedPreKey] = keys;
if (preKey == undefined || signedPreKey == undefined) {
log.error("Will need to request keys!")
}
else {
const identityKey = StringView.hexToArrayBuffer(number);
return handleResult({ identityKey, devices: [{ deviceId: device, preKey, signedPreKey, registrationId: 0}] })
}
})
const [preKey, signedPreKey] = keys;
if (preKey == undefined || signedPreKey == undefined) {
log.error("Will need to request keys!")
this.fallBackEncryption = true;
return Promise.resolve();
}
else {
const identityKey = StringView.hexToArrayBuffer(number);
return handleResult({ identityKey, devices: [{ deviceId: device, preKey, signedPreKey, registrationId: 0 }] })
}
})
.catch(e => {
if (e.name === 'HTTPError' && e.code === 404) {
if (device !== 1) {
@ -153,7 +157,7 @@ OutgoingMessage.prototype = {
const [response, status] = await this.lokiserver.sendMessage(pubKey, JSON.stringify(jsonData), ttl);
return response;
}
catch(e) {
catch (e) {
if (e.name === 'HTTPError' && (e.code !== 409 && e.code !== 410)) {
// 409 and 410 should bubble and be handled by doSendMessage
// 404 should throw UnregisteredUserError
@ -186,11 +190,13 @@ OutgoingMessage.prototype = {
getPlaintext() {
if (!this.plaintext) {
const messageBuffer = this.message.toArrayBuffer();
this.plaintext = new Uint8Array(
this.getPaddedMessageLength(messageBuffer.byteLength + 1) - 1
);
this.plaintext = new Uint8Array(messageBuffer.byteLength);
// 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[messageBuffer.byteLength] = 0x80;
//this.plaintext[messageBuffer.byteLength] = 0x80;
}
return this.plaintext;
},
@ -211,11 +217,43 @@ OutgoingMessage.prototype = {
options.messageKeysLimit = false;
}
const sessionCipher = new libsignal.SessionCipher(
textsecure.storage.protocol,
address,
options
);
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,
address,
options
);
}
ciphers[address.getDeviceId()] = sessionCipher;
return sessionCipher.encrypt(plaintext).then(ciphertext => ({
type: ciphertext.type,

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

Loading…
Cancel
Save