diff --git a/test/crypto_test.js b/test/crypto_test.js
index 0f57e315c..307cafda0 100644
--- a/test/crypto_test.js
+++ b/test/crypto_test.js
@@ -16,18 +16,7 @@
'use strict';
-describe("ArrayBuffer->String conversion", function() {
- it('works', function() {
- var b = new ArrayBuffer(3);
- var a = new Uint8Array(b);
- a[0] = 0;
- a[1] = 255;
- a[2] = 128;
- assert.equal(getString(b), "\x00\xff\x80");
- });
-});
-
-describe("Cryptographic primitives", function() {
+describe("Crypto", function() {
describe("Encrypt AES-CBC", function() {
it('works', function(done) {
var key = hexToArrayBuffer('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4');
@@ -86,45 +75,14 @@ describe("Cryptographic primitives", function() {
}).then(done).catch(done);
});
});
-});
-describe('Unencrypted PushMessageProto "decrypt"', function() {
- //exclusive
- it('works', function(done) {
- localStorage.clear();
- var PushMessageProto = dcodeIO.ProtoBuf.loadProtoFile(
- "protos/IncomingPushMessageSignal.proto"
- ).build("textsecure.PushMessageContent");
- var IncomingMessageProto = dcodeIO.ProtoBuf.loadProtoFile(
- "protos/IncomingPushMessageSignal.proto"
- ).build("textsecure.IncomingPushMessageSignal");
-
- var text_message = new PushMessageProto();
- text_message.body = "Hi Mom";
- var server_message = {
- type: 4, // unencrypted
- source: "+19999999999",
- timestamp: 42,
- message: text_message.encode()
- };
-
- return textsecure.protocol.handleIncomingPushMessageProto(server_message).
- then(function(message) {
- assert.equal(message.body, text_message.body);
- assert.equal(message.attachments.length, text_message.attachments.length);
- assert.equal(text_message.attachments.length, 0);
- }).then(done).catch(done);
- });
-});
-
-describe("Curve25519", function() {
- describe("Implementation", function() {
+ describe("Curve25519 implementation", function() {
// this is a just cute little trick to get a nice-looking note about
// which curve25519 impl we're using.
if (window.textsecure.NATIVE_CLIENT) {
- it("is Native Client", function(done) { done(); });
+ it("is Native Client", function() {});
} else {
- it("is JavaScript", function(done) { done(); });
+ it("is JavaScript", function() {});
}
});
@@ -190,200 +148,4 @@ describe("Curve25519", function() {
}).then(done).catch(done);
});
});
-
- describe("Identity and Pre Key Creation", function() {
- this.timeout(10000);
- before(function() { localStorage.clear(); });
- after(function() { localStorage.clear(); });
- it ('works', function(done) {
- localStorage.clear();
- return textsecure.registerOnLoadFunction(function() {
- return textsecure.protocol.generateKeys().then(function() {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
- assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
- for (var i = 0; i < 100; i++) {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
- }
- var origIdentityKey = getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey);
- return textsecure.protocol.generateKeys().then(function() {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
- assert.equal(getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey), origIdentityKey);
-
- assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
- assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey1"));
-
- for (var i = 0; i < 200; i++) {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
- }
-
- return textsecure.protocol.generateKeys().then(function() {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
- assert.equal(getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey), origIdentityKey);
-
- assert.isUndefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
- assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey1"));
- assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey2"));
-
- for (var i = 0; i < 300; i++) {
- assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
- }
- });
- });
- });
- }).then(done).catch(done);
- });
- });
});
-
-describe("Axolotl", function() {
- var runAxolotlTest = function(v) {
- var origCreateNewKeyPair = textsecure.crypto.testing_only.createNewKeyPair;
- var doStep;
- var stepDone;
-
- stepDone = function(res) {
- if (!res || privKeyQueue.length != 0 || Object.keys(getKeysForNumberMap).length != 0 || Object.keys(messagesSentMap).length != 0) {
- textsecure.crypto.testing_only.createNewKeyPair = origCreateNewKeyPair;
- return false;
- } else if (step == v.length) {
- textsecure.crypto.testing_only.createNewKeyPair = origCreateNewKeyPair;
- return true;
- } else
- return doStep().then(stepDone);
- }
-
- var privKeyQueue = [];
- textsecure.crypto.testing_only.createNewKeyPair = function(isIdentity) {
- if (privKeyQueue.length == 0 || isIdentity)
- throw new Error('Out of private keys');
- else {
- var privKey = privKeyQueue.shift();
- return textsecure.crypto.createKeyPair(privKey).then(function(keyPair) {
- var a = btoa(getString(keyPair.privKey)); var b = btoa(getString(privKey));
- if (getString(keyPair.privKey) != getString(privKey))
- throw new Error('Failed to rederive private key!');
- else
- return keyPair;
- });
- }
- }
-
- var step = 0;
- var doStep = function() {
- var data = v[step][1];
-
- switch(v[step++][0]) {
- case "receiveMessage":
- var postLocalKeySetup = function() {
- if (data.newEphemeralKey !== undefined)
- privKeyQueue.push(data.newEphemeralKey);
-
- var message = new textsecure.protobuf.IncomingPushMessageSignal();
- message.type = data.type;
- message.source = "SNOWDEN";
- message.message = data.message;
- message.sourceDevice = 1;
- try {
- var proto = textsecure.protobuf.IncomingPushMessageSignal.decode(message.encode());
- return textsecure.protocol.handleIncomingPushMessageProto(proto).then(function(res) {
- if (data.expectTerminateSession)
- return res.flags == textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
- return res.body == data.expectedSmsText;
- }).catch(function(e) {
- if (data.expectException)
- return true;
- throw e;
- });
- } catch(e) {
- if (data.expectException)
- return Promise.resolve(true);
- throw e;
- }
- }
-
- if (data.ourIdentityKey !== undefined)
- return textsecure.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
- textsecure.storage.putEncrypted("25519KeyidentityKey", keyPair);
- return textsecure.crypto.createKeyPair(data.ourSignedPreKey).then(function(keyPair) {
- textsecure.storage.putEncrypted("25519KeysignedKey" + data.signedPreKeyId, keyPair);
-
- if (data.ourPreKey !== undefined)
- return textsecure.crypto.createKeyPair(data.ourPreKey).then(function(keyPair) {
- textsecure.storage.putEncrypted("25519KeypreKey" + data.preKeyId, keyPair);
- return postLocalKeySetup();
- });
- else
- return postLocalKeySetup();
- });
- });
- else
- return postLocalKeySetup();
-
- case "sendMessage":
- var postLocalKeySetup = function() {
- if (data.registrationId !== undefined)
- textsecure.storage.putUnencrypted("registrationId", data.registrationId);
-
- if (data.getKeys !== undefined)
- getKeysForNumberMap["SNOWDEN"] = data.getKeys;
-
- var checkMessage = function() {
- var msg = messagesSentMap["SNOWDEN.1"];
- delete messagesSentMap["SNOWDEN.1"];
- //XXX: This should be all we do: isEqual(data.expectedCiphertext, msg.body, false);
- if (msg.type == 1) {
- var expected = getString(data.expectedCiphertext);
- var decoded = textsecure.protobuf.WhisperMessage.decode(expected.substring(1, expected.length - 8), 'binary');
- var result = getString(msg.body);
- return getString(decoded.encode()) == result.substring(1, result.length - 8);
- } else {
- var decoded = textsecure.protobuf.PreKeyWhisperMessage.decode(getString(data.expectedCiphertext).substr(1), 'binary');
- var result = getString(msg.body).substring(1);
- return getString(decoded.encode()) == result;
- }
- }
-
- if (data.endSession)
- return textsecure.messaging.closeSession("SNOWDEN").then(checkMessage);
- else
- return textsecure.messaging.sendMessageToNumber("SNOWDEN", data.smsText, []).then(checkMessage);
- }
-
- if (data.ourBaseKey !== undefined)
- privKeyQueue.push(data.ourBaseKey);
- if (data.ourEphemeralKey !== undefined)
- privKeyQueue.push(data.ourEphemeralKey);
-
- if (data.ourIdentityKey !== undefined)
- return textsecure.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
- textsecure.storage.putEncrypted("25519KeyidentityKey", keyPair);
- return postLocalKeySetup();
- });
- else
- return postLocalKeySetup();
-
- default:
- return Promise.resolve(false);
- }
- }
- return doStep().then(stepDone);
- };
-
- describe("test vectors", function() {
- _.each(axolotlTestVectors, function(t, i) {
- it(t.name, function(done) {
- localStorage.clear();
- return textsecure.registerOnLoadFunction(function() {
- return runAxolotlTest(t.vectors).then(function(res) {
- assert(res);
- });
- }).then(done).catch(done);
- });
- });
- });
-});
-
-if (window.mochaPhantomJS)
- mochaPhantomJS.run();
-else
- mocha.run();
diff --git a/test/helpers_test.js b/test/helpers_test.js
new file mode 100644
index 000000000..2f54eb80f
--- /dev/null
+++ b/test/helpers_test.js
@@ -0,0 +1,30 @@
+/* vim: ts=4:sw=4
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+describe("Helpers", function() {
+ describe("ArrayBuffer->String conversion", function() {
+ it('works', function() {
+ var b = new ArrayBuffer(3);
+ var a = new Uint8Array(b);
+ a[0] = 0;
+ a[1] = 255;
+ a[2] = 128;
+ assert.equal(getString(b), "\x00\xff\x80");
+ });
+ });
+});
diff --git a/test/index.html b/test/index.html
index 875bcf155..b23555e38 100644
--- a/test/index.html
+++ b/test/index.html
@@ -157,7 +157,9 @@
+
+
diff --git a/test/protocol_test.js b/test/protocol_test.js
new file mode 100644
index 000000000..bd80bd6de
--- /dev/null
+++ b/test/protocol_test.js
@@ -0,0 +1,240 @@
+/* vim: ts=4:sw=4
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+describe('Protocol', function() {
+
+ describe('Unencrypted PushMessageProto "decrypt"', function() {
+ //exclusive
+ it('works', function(done) {
+ localStorage.clear();
+ var PushMessageProto = dcodeIO.ProtoBuf.loadProtoFile(
+ "protos/IncomingPushMessageSignal.proto"
+ ).build("textsecure.PushMessageContent");
+ var IncomingMessageProto = dcodeIO.ProtoBuf.loadProtoFile(
+ "protos/IncomingPushMessageSignal.proto"
+ ).build("textsecure.IncomingPushMessageSignal");
+
+ var text_message = new PushMessageProto();
+ text_message.body = "Hi Mom";
+ var server_message = {
+ type: 4, // unencrypted
+ source: "+19999999999",
+ timestamp: 42,
+ message: text_message.encode()
+ };
+
+ return textsecure.protocol.handleIncomingPushMessageProto(server_message).
+ then(function(message) {
+ assert.equal(message.body, text_message.body);
+ assert.equal(message.attachments.length, text_message.attachments.length);
+ assert.equal(text_message.attachments.length, 0);
+ }).then(done).catch(done);
+ });
+ });
+
+
+ describe("Identity and Pre Key Creation", function() {
+ this.timeout(10000);
+ before(function() { localStorage.clear(); });
+ after(function() { localStorage.clear(); });
+ it ('works', function(done) {
+ localStorage.clear();
+ return textsecure.registerOnLoadFunction(function() {
+ return textsecure.protocol.generateKeys().then(function() {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
+ for (var i = 0; i < 100; i++) {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
+ }
+ var origIdentityKey = getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey);
+ return textsecure.protocol.generateKeys().then(function() {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
+ assert.equal(getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey), origIdentityKey);
+
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey1"));
+
+ for (var i = 0; i < 200; i++) {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
+ }
+
+ return textsecure.protocol.generateKeys().then(function() {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeyidentityKey"));
+ assert.equal(getString(textsecure.storage.getEncrypted("25519KeyidentityKey").privKey), origIdentityKey);
+
+ assert.isUndefined(textsecure.storage.getEncrypted("25519KeysignedKey0"));
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey1"));
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeysignedKey2"));
+
+ for (var i = 0; i < 300; i++) {
+ assert.isDefined(textsecure.storage.getEncrypted("25519KeypreKey" + i));
+ }
+ });
+ });
+ });
+ }).then(done).catch(done);
+ });
+ });
+
+ describe("Axolotl", function() {
+ var runAxolotlTest = function(v) {
+ var origCreateNewKeyPair = textsecure.crypto.testing_only.createNewKeyPair;
+ var doStep;
+ var stepDone;
+
+ stepDone = function(res) {
+ if (!res || privKeyQueue.length != 0 || Object.keys(getKeysForNumberMap).length != 0 || Object.keys(messagesSentMap).length != 0) {
+ textsecure.crypto.testing_only.createNewKeyPair = origCreateNewKeyPair;
+ return false;
+ } else if (step == v.length) {
+ textsecure.crypto.testing_only.createNewKeyPair = origCreateNewKeyPair;
+ return true;
+ } else
+ return doStep().then(stepDone);
+ }
+
+ var privKeyQueue = [];
+ textsecure.crypto.testing_only.createNewKeyPair = function(isIdentity) {
+ if (privKeyQueue.length == 0 || isIdentity)
+ throw new Error('Out of private keys');
+ else {
+ var privKey = privKeyQueue.shift();
+ return textsecure.crypto.createKeyPair(privKey).then(function(keyPair) {
+ var a = btoa(getString(keyPair.privKey)); var b = btoa(getString(privKey));
+ if (getString(keyPair.privKey) != getString(privKey))
+ throw new Error('Failed to rederive private key!');
+ else
+ return keyPair;
+ });
+ }
+ }
+
+ var step = 0;
+ var doStep = function() {
+ var data = v[step][1];
+
+ switch(v[step++][0]) {
+ case "receiveMessage":
+ var postLocalKeySetup = function() {
+ if (data.newEphemeralKey !== undefined)
+ privKeyQueue.push(data.newEphemeralKey);
+
+ var message = new textsecure.protobuf.IncomingPushMessageSignal();
+ message.type = data.type;
+ message.source = "SNOWDEN";
+ message.message = data.message;
+ message.sourceDevice = 1;
+ try {
+ var proto = textsecure.protobuf.IncomingPushMessageSignal.decode(message.encode());
+ return textsecure.protocol.handleIncomingPushMessageProto(proto).then(function(res) {
+ if (data.expectTerminateSession)
+ return res.flags == textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
+ return res.body == data.expectedSmsText;
+ }).catch(function(e) {
+ if (data.expectException)
+ return true;
+ throw e;
+ });
+ } catch(e) {
+ if (data.expectException)
+ return Promise.resolve(true);
+ throw e;
+ }
+ }
+
+ if (data.ourIdentityKey !== undefined)
+ return textsecure.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
+ textsecure.storage.putEncrypted("25519KeyidentityKey", keyPair);
+ return textsecure.crypto.createKeyPair(data.ourSignedPreKey).then(function(keyPair) {
+ textsecure.storage.putEncrypted("25519KeysignedKey" + data.signedPreKeyId, keyPair);
+
+ if (data.ourPreKey !== undefined)
+ return textsecure.crypto.createKeyPair(data.ourPreKey).then(function(keyPair) {
+ textsecure.storage.putEncrypted("25519KeypreKey" + data.preKeyId, keyPair);
+ return postLocalKeySetup();
+ });
+ else
+ return postLocalKeySetup();
+ });
+ });
+ else
+ return postLocalKeySetup();
+
+ case "sendMessage":
+ var postLocalKeySetup = function() {
+ if (data.registrationId !== undefined)
+ textsecure.storage.putUnencrypted("registrationId", data.registrationId);
+
+ if (data.getKeys !== undefined)
+ getKeysForNumberMap["SNOWDEN"] = data.getKeys;
+
+ var checkMessage = function() {
+ var msg = messagesSentMap["SNOWDEN.1"];
+ delete messagesSentMap["SNOWDEN.1"];
+ //XXX: This should be all we do: isEqual(data.expectedCiphertext, msg.body, false);
+ if (msg.type == 1) {
+ var expected = getString(data.expectedCiphertext);
+ var decoded = textsecure.protobuf.WhisperMessage.decode(expected.substring(1, expected.length - 8), 'binary');
+ var result = getString(msg.body);
+ return getString(decoded.encode()) == result.substring(1, result.length - 8);
+ } else {
+ var decoded = textsecure.protobuf.PreKeyWhisperMessage.decode(getString(data.expectedCiphertext).substr(1), 'binary');
+ var result = getString(msg.body).substring(1);
+ return getString(decoded.encode()) == result;
+ }
+ }
+
+ if (data.endSession)
+ return textsecure.messaging.closeSession("SNOWDEN").then(checkMessage);
+ else
+ return textsecure.messaging.sendMessageToNumber("SNOWDEN", data.smsText, []).then(checkMessage);
+ }
+
+ if (data.ourBaseKey !== undefined)
+ privKeyQueue.push(data.ourBaseKey);
+ if (data.ourEphemeralKey !== undefined)
+ privKeyQueue.push(data.ourEphemeralKey);
+
+ if (data.ourIdentityKey !== undefined)
+ return textsecure.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
+ textsecure.storage.putEncrypted("25519KeyidentityKey", keyPair);
+ return postLocalKeySetup();
+ });
+ else
+ return postLocalKeySetup();
+
+ default:
+ return Promise.resolve(false);
+ }
+ }
+ return doStep().then(stepDone);
+ };
+
+ describe("test vectors", function() {
+ _.each(axolotlTestVectors, function(t, i) {
+ it(t.name, function(done) {
+ localStorage.clear();
+ return textsecure.registerOnLoadFunction(function() {
+ return runAxolotlTest(t.vectors).then(function(res) {
+ assert(res);
+ });
+ }).then(done).catch(done);
+ });
+ });
+ });
+ });
+});