diff --git a/.eslintignore b/.eslintignore
index ff968ce0e..6ef379a1c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -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
diff --git a/.gitignore b/.gitignore
index b1b7020d1..586046d86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/.prettierignore b/.prettierignore
index 756580e19..e6db8458c 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -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
diff --git a/Gruntfile.js b/Gruntfile.js
index 77815ff86..b05512dac 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -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'],
diff --git a/background.html b/background.html
index ac4c1869c..8af81e984 100644
--- a/background.html
+++ b/background.html
@@ -584,6 +584,7 @@
+
diff --git a/libloki/libloki-protocol.js b/libloki/libloki-protocol.js
new file mode 100644
index 000000000..5cf9e5cfe
--- /dev/null
+++ b/libloki/libloki-protocol.js
@@ -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;
+
+})();
\ No newline at end of file
diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js
index 7217c0f36..6381a173c 100644
--- a/libtextsecure/message_receiver.js
+++ b/libtextsecure/message_receiver.js
@@ -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(
diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js
index 25915c630..723e8c7bd 100644
--- a/libtextsecure/outgoing_message.js
+++ b/libtextsecure/outgoing_message.js
@@ -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 {
diff --git a/mockup_servers/socket_server.py b/mockup_servers/socket_server.py
index e35fd7861..47a0da0b6 100644
--- a/mockup_servers/socket_server.py
+++ b/mockup_servers/socket_server.py
@@ -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:[]})
diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts
index c274aadb9..29bc5f939 100644
--- a/ts/util/lint/linter.ts
+++ b/ts/util/lint/linter.ts
@@ -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',