Merge pull request #7 from sachaaaaa/fallback_decrypt

Decrypt "friend request" messages using fallback encryption. Move logic into libloki.js
This commit is contained in:
sachaaaaa 2018-10-11 14:10:44 +11:00 committed by GitHub
commit b52dac98b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 31 deletions

View file

@ -12,6 +12,7 @@ test/views/*.js
# Generated files
js/components.js
js/libtextsecure.js
js/libloki.js
js/util_worker.js
js/libsignal-protocol-worker.js
libtextsecure/components.js

1
.gitignore vendored
View file

@ -19,6 +19,7 @@ sql/
js/components.js
js/util_worker.js
js/libtextsecure.js
js/libloki.js
libtextsecure/components.js
libtextsecure/test/test.js
stylesheets/*.css

View file

@ -8,6 +8,7 @@ dist/**
js/components.js
js/util_worker.js
js/libtextsecure.js
js/libloki.js
libtextsecure/components.js
libtextsecure/test/test.js
stylesheets/*.css

View file

@ -86,6 +86,12 @@ module.exports = grunt => {
],
dest: 'js/libtextsecure.js',
},
libloki: {
src: [
'libloki/libloki-protocol.js',
],
dest: 'js/libloki.js',
},
libtextsecuretest: {
src: [
'node_modules/jquery/dist/jquery.js',
@ -128,6 +134,10 @@ module.exports = grunt => {
files: ['./libtextsecure/*.js', './libtextsecure/storage/*.js'],
tasks: ['concat:libtextsecure'],
},
libloki: {
files: ['./libloki/*.js'],
tasks: ['concat:libloki'],
},
protobuf: {
files: ['./protos/SignalService.proto'],
tasks: ['exec:build-protobuf'],

View file

@ -584,6 +584,7 @@
<script type='text/javascript' src='js/storage.js'></script>
<script type='text/javascript' src='js/signal_protocol_store.js'></script>
<script type='text/javascript' src='js/libtextsecure.js'></script>
<script type='text/javascript' src='js/libloki.js'></script>
<script type='text/javascript' src='js/focus_listener.js'></script>
<script type='text/javascript' src='js/notifications.js'></script>

View file

@ -0,0 +1,47 @@
/* global window, libsignal, textsecure */
// eslint-disable-next-line func-names
(function() {
window.libloki = window.libloki || {};
const IV_LENGTH = 16;
FallBackSessionCipher = function (address) {
this.pubKey = 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.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 : 6, //friend request
body : new dcodeIO.ByteBuffer.wrap(ivAndCiphertext).toString('binary'),
registrationId : null
};
},
this.decrypt = async (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);
const plaintext = await libsignal.crypto.decrypt(symmetricKey, cipherText, iv);
return plaintext;
}
}
window.libloki.FallBackSessionCipher = FallBackSessionCipher;
})();

View file

@ -646,10 +646,17 @@ 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
// TODO: restore decryption & unpadding (?)
//.decryptWhisperMessage(ciphertext)
//.then(this.unpad);
break;
case textsecure.protobuf.Envelope.Type.FRIEND_REQUEST:
window.log.info('friend-request message from ', envelope.source)
const fallBackSessionCipher = new libloki.FallBackSessionCipher(
address
);
promise = fallBackSessionCipher.decrypt(ciphertext.toArrayBuffer());
break;
case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE:
window.log.info('prekey message from', this.getEnvelopeId(envelope));
promise = this.decryptPreKeyWhisperMessage(

View file

@ -1,4 +1,4 @@
/* global textsecure, libsignal, window, btoa */
/* global textsecure, libsignal, window, btoa, libloki */
/* eslint-disable more/no-then */
@ -209,7 +209,7 @@ OutgoingMessage.prototype = {
content: outgoingObject.content,
});
const requestMessage = new textsecure.protobuf.WebSocketRequestMessage({
id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0],
id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0], // random ID for now
verb: 'PUT',
path: '/api/v1/message',
body: messageEnvelope.encode().toArrayBuffer()
@ -219,6 +219,7 @@ OutgoingMessage.prototype = {
request: requestMessage
});
const bytes = new Uint8Array(websocketMessage.encode().toArrayBuffer())
bytes.toString(); // print bytes for debugging purposes: can be injected in mock socket server
return bytes;
},
doSendMessage(number, deviceIds, recurse) {
@ -239,32 +240,7 @@ OutgoingMessage.prototype = {
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(
sessionCipher = new libloki.FallBackSessionCipher(
address
);
} else {

View file

@ -13,9 +13,11 @@ async def hello(websocket, path):
# protomessage = new textsecure.protobuf.WebSocketMessage({type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, request: {id:99, verb:'PUT', path:'/api/v1/queue/empty', body:null }})
# new Uint8Array(protomessage.encode().toArrayBuffer())
message = bytes(
#[8, 1, 18, 70, 10, 3, 80, 85, 84, 18, 15, 47, 97, 112, 105, 47, 118, 49, 47, 109, 101, 115, 115, 97, 103, 101, 26, 44, 8, 1, 18, 15, 109, 121, 115, 111, 117, 114, 99, 101, 97, 100, 100, 114, 101, 115, 115, 56, 1, 40, 184, 151, 213, 221, 5, 66, 15, 10, 13, 10, 11, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 99]
[
8,1,18,117,10,3,80,85,84,18,15,47,97,112,105,47,118,49,47,109,101,115,115,97,103,101,26,91,8,1,18,66,48,53,55,51,57,102,51,54,55,50,100,55,57,52,51,56,101,57,53,53,97,55,99,99,55,55,56,52,100,98,97,53,101,97,52,98,102,56,50,55,52,54,54,53,55,55,51,99,97,102,51,101,97,98,55,48,97,50,98,57,100,98,102,101,50,99,56,1,40,0,66,15,10,13,10,11,104,101,108,108,111,32,119,111,114,108,100,32,99
# "hello world" - unencrypted
#8,1,18,117,10,3,80,85,84,18,15,47,97,112,105,47,118,49,47,109,101,115,115,97,103,101,26,91,8,1,18,66,48,53,55,51,57,102,51,54,55,50,100,55,57,52,51,56,101,57,53,53,97,55,99,99,55,55,56,52,100,98,97,53,101,97,52,98,102,56,50,55,52,54,54,53,55,55,51,99,97,102,51,101,97,98,55,48,97,50,98,57,100,98,102,101,50,99,56,1,40,0,66,15,10,13,10,11,104,101,108,108,111,32,119,111,114,108,100,32,99
# "test" - fall back encrypted
8,1,18,140,1,10,3,80,85,84,18,15,47,97,112,105,47,118,49,47,109,101,115,115,97,103,101,26,113,8,6,18,66,48,53,51,102,48,101,57,56,54,53,97,100,101,54,97,100,57,48,48,97,54,99,101,51,98,98,54,101,102,97,99,102,102,102,97,98,99,50,56,49,101,53,97,50,102,100,102,54,101,97,49,51,57,98,51,48,51,50,49,55,57,57,97,97,50,99,56,1,40,181,202,171,141,229,44,66,32,147,127,63,203,38,142,133,120,28,115,7,150,230,26,166,28,182,199,199,182,11,101,80,48,252,232,108,164,8,236,98,50,32,150,1
])
# created by executing in js:
# dataMessage = new textsecure.protobuf.DataMessage({body: "hello world", attachments:[], contact:[]})

View file

@ -52,6 +52,7 @@ const excludedFiles = [
// Generated files
'^js/components.js',
'^js/libtextsecure.js',
'^js/libloki.js',
'^js/util_worker.js',
'^libtextsecure/components.js',
'^libtextsecure/test/test.js',