Move test vectors to libaxolotl
This commit is contained in:
parent
7e3f1ef452
commit
298c8624b2
8 changed files with 404 additions and 217 deletions
43
libaxolotl/test/fake_api.js
Normal file
43
libaxolotl/test/fake_api.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var testSessionMap = {};
|
||||||
|
|
||||||
|
;(function() {
|
||||||
|
window.axolotl = window.axolotl || {};
|
||||||
|
window.axolotl.api = {
|
||||||
|
getMyRegistrationId: function() {
|
||||||
|
return window.myRegistrationId;
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
put: function(key, value) {
|
||||||
|
if (value === undefined)
|
||||||
|
throw new Error("Tried to store undefined");
|
||||||
|
localStorage.setItem(key, textsecure.utils.jsonThing(value));
|
||||||
|
},
|
||||||
|
get: function(key, defaultValue) {
|
||||||
|
var value = localStorage.getItem(key);
|
||||||
|
if (value === null)
|
||||||
|
return defaultValue;
|
||||||
|
return JSON.parse(value);
|
||||||
|
},
|
||||||
|
remove: function(key) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
},
|
||||||
|
|
||||||
|
sessions: {
|
||||||
|
get: function(identifier) {
|
||||||
|
return testSessionMap[identifier];
|
||||||
|
},
|
||||||
|
put: function(identifier, record) {
|
||||||
|
testSessionMap[identifier] = record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateKeys: function(keys) {
|
||||||
|
return textsecure.api.registerKeys(keys).catch(function(e) {
|
||||||
|
//TODO: Notify the user somehow?
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
|
@ -29,12 +29,22 @@
|
||||||
<script type="text/javascript" src="test.js"></script>
|
<script type="text/javascript" src="test.js"></script>
|
||||||
<script type="text/javascript" src="blanket_mocha.js"></script>
|
<script type="text/javascript" src="blanket_mocha.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="../components.js"></script>
|
|
||||||
<script type="text/javascript" src="../curve25519_concat.js"></script>
|
<script type="text/javascript" src="../curve25519_concat.js"></script>
|
||||||
<script type="text/javascript" src="../webcrypto_concat.js"></script>
|
<script type="text/javascript" src="../webcrypto_concat.js"></script>
|
||||||
|
<script type="text/javascript" src="../components.js"></script>
|
||||||
|
|
||||||
|
<!-- TODO: Remove the following -->
|
||||||
|
<script type="text/javascript" src="temp_helpers.js"></script>
|
||||||
|
<script type="text/javascript" src="../../libtextsecure/protobufs.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="../crypto.js" data-cover></script>
|
<script type="text/javascript" src="../crypto.js" data-cover></script>
|
||||||
|
<script type="text/javascript" src="../protocol.js" data-cover></script>
|
||||||
|
<script type="text/javascript" src="../protobufs.js" data-cover></script>
|
||||||
|
<script type="text/javascript" src="../session_storage.js" data-cover></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="fake_api.js"></script>
|
||||||
<script type="text/javascript" src="crypto_test.js"></script>
|
<script type="text/javascript" src="crypto_test.js"></script>
|
||||||
|
<script type="text/javascript" src="testvectors.js"></script>
|
||||||
|
<script type="text/javascript" src="protocol_test.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
236
libaxolotl/test/protocol_test.js
Normal file
236
libaxolotl/test/protocol_test.js
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
/* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
describe('Protocol', function() {
|
||||||
|
|
||||||
|
describe("Identity and Pre Key Creation", function() {
|
||||||
|
this.timeout(200000);
|
||||||
|
before(function() { localStorage.clear(); });
|
||||||
|
after(function() { localStorage.clear(); });
|
||||||
|
it ('works', function(done) {
|
||||||
|
localStorage.clear();
|
||||||
|
return axolotl.protocol.generateKeys().then(function() {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeyidentityKey"));
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeysignedKey0"));
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeypreKey" + i));
|
||||||
|
}
|
||||||
|
var origIdentityKey = getString(axolotl.api.storage.get("25519KeyidentityKey").privKey);
|
||||||
|
return axolotl.protocol.generateKeys().then(function() {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeyidentityKey"));
|
||||||
|
assert.equal(getString(axolotl.api.storage.get("25519KeyidentityKey").privKey), origIdentityKey);
|
||||||
|
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeysignedKey0"));
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeysignedKey1"));
|
||||||
|
|
||||||
|
for (var i = 0; i < 200; i++) {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeypreKey" + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return axolotl.protocol.generateKeys().then(function() {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeyidentityKey"));
|
||||||
|
assert.equal(getString(axolotl.api.storage.get("25519KeyidentityKey").privKey), origIdentityKey);
|
||||||
|
|
||||||
|
assert.isUndefined(axolotl.api.storage.get("25519KeysignedKey0"));
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeysignedKey1"));
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeysignedKey2"));
|
||||||
|
|
||||||
|
for (var i = 0; i < 300; i++) {
|
||||||
|
assert.isDefined(axolotl.api.storage.get("25519KeypreKey" + i));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).then(done).catch(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Axolotl", function() {
|
||||||
|
var runAxolotlTest = function(v) {
|
||||||
|
var origCreateKeyPair = axolotl.crypto.createKeyPair;
|
||||||
|
var doStep;
|
||||||
|
var stepDone;
|
||||||
|
|
||||||
|
stepDone = function(res) {
|
||||||
|
if (!res || privKeyQueue.length != 0) {
|
||||||
|
axolotl.crypto.createKeyPair = origCreateKeyPair;
|
||||||
|
return false;
|
||||||
|
} else if (step == v.length) {
|
||||||
|
axolotl.crypto.createKeyPair = origCreateKeyPair;
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return doStep().then(stepDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
var privKeyQueue = [];
|
||||||
|
axolotl.crypto.createKeyPair = function(privKey) {
|
||||||
|
if (privKey !== undefined)
|
||||||
|
return origCreateKeyPair(privKey);
|
||||||
|
if (privKeyQueue.length == 0)
|
||||||
|
throw new Error('Out of private keys');
|
||||||
|
else {
|
||||||
|
var privKey = privKeyQueue.shift();
|
||||||
|
return axolotl.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 deviceObject = {encodedNumber: "SNOWDEN.1"};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
try {
|
||||||
|
var checkResult = function(res) {
|
||||||
|
res = textsecure.protobuf.PushMessageContent.decode(res[0]);
|
||||||
|
//TODO: Handle END_SESSION here (just like libtextsecure.protocol_wrapper
|
||||||
|
if (data.expectTerminateSession)
|
||||||
|
return res.flags == textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
|
||||||
|
return res.body == data.expectedSmsText;
|
||||||
|
}
|
||||||
|
var checkException = function(e) {
|
||||||
|
if (data.expectException)
|
||||||
|
return true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.type == textsecure.protobuf.IncomingPushMessageSignal.Type.CIPHERTEXT)
|
||||||
|
return axolotl.protocol.decryptWhisperMessage("SNOWDEN.1", getString(data.message)).then(checkResult).catch(checkException);
|
||||||
|
else if (data.type == textsecure.protobuf.IncomingPushMessageSignal.Type.PREKEY_BUNDLE) {
|
||||||
|
if (getString(data.message).charCodeAt(0) != ((3 << 4) | 3))
|
||||||
|
throw new Error("Bad version byte");
|
||||||
|
return axolotl.protocol.handlePreKeyWhisperMessage("SNOWDEN.1", getString(data.message).substring(1)).then(checkResult).catch(checkException);
|
||||||
|
} else
|
||||||
|
return Promise.reject(new Error("Unknown data type in test vector"));
|
||||||
|
} catch(e) {
|
||||||
|
if (data.expectException)
|
||||||
|
return Promise.resolve(true);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.ourIdentityKey !== undefined)
|
||||||
|
return axolotl.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
|
||||||
|
axolotl.api.storage.put("25519KeyidentityKey", keyPair);
|
||||||
|
return axolotl.crypto.createKeyPair(data.ourSignedPreKey).then(function(keyPair) {
|
||||||
|
axolotl.api.storage.put("25519KeysignedKey" + data.signedPreKeyId, keyPair);
|
||||||
|
|
||||||
|
if (data.ourPreKey !== undefined)
|
||||||
|
return axolotl.crypto.createKeyPair(data.ourPreKey).then(function(keyPair) {
|
||||||
|
axolotl.api.storage.put("25519KeypreKey" + data.preKeyId, keyPair);
|
||||||
|
return postLocalKeySetup();
|
||||||
|
});
|
||||||
|
else
|
||||||
|
return postLocalKeySetup();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
else
|
||||||
|
return postLocalKeySetup();
|
||||||
|
|
||||||
|
case "sendMessage":
|
||||||
|
var postLocalKeySetup = function() {
|
||||||
|
if (data.registrationId !== undefined)
|
||||||
|
window.myRegistrationId = data.registrationId;
|
||||||
|
|
||||||
|
if (data.getKeys !== undefined) {
|
||||||
|
deviceObject = {encodedNumber: "SNOWDEN.1",
|
||||||
|
identityKey: data.getKeys.identityKey,
|
||||||
|
preKey: data.getKeys.devices[0].preKey.publicKey,
|
||||||
|
preKeyId: data.getKeys.devices[0].preKey.keyId,
|
||||||
|
signedKey: data.getKeys.devices[0].signedPreKey.publicKey,
|
||||||
|
signedKeyId: data.getKeys.devices[0].signedPreKey.keyId,
|
||||||
|
signedKeySignature: data.getKeys.devices[0].signedPreKey.signature,
|
||||||
|
registrationId: data.getKeys.devices[0].signedPreKey.keyId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkMessage = function(msg) {
|
||||||
|
//XXX: This should be all we do: isEqual(data.expectedCiphertext, encryptedMsg, false);
|
||||||
|
var encryptedMsg = msg.body;
|
||||||
|
if (msg.type == 1) {
|
||||||
|
var expected = getString(data.expectedCiphertext);
|
||||||
|
var decoded = axolotl.protobuf.WhisperMessage.decode(expected.substring(1, expected.length - 8), 'binary');
|
||||||
|
var result = getString(encryptedMsg);
|
||||||
|
return getString(decoded.encode()) == result.substring(1, result.length - 8);
|
||||||
|
} else {
|
||||||
|
var decoded = axolotl.protobuf.PreKeyWhisperMessage.decode(getString(data.expectedCiphertext).substr(1), 'binary');
|
||||||
|
var result = getString(encryptedMsg).substring(1);
|
||||||
|
return getString(decoded.encode()) == result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var proto = new textsecure.protobuf.PushMessageContent();
|
||||||
|
if (data.endSession) {
|
||||||
|
proto.flags = textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
|
||||||
|
proto.body = "TERMINATE";
|
||||||
|
} else
|
||||||
|
proto.body = data.smsText;
|
||||||
|
|
||||||
|
return axolotl.protocol.encryptMessageFor(deviceObject, proto).then(checkMessage)
|
||||||
|
.then(function(res) {
|
||||||
|
if (data.endSession)
|
||||||
|
axolotl.protocol.closeOpenSessionForDevice("SNOWDEN.1");
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.ourBaseKey !== undefined)
|
||||||
|
privKeyQueue.push(data.ourBaseKey);
|
||||||
|
if (data.ourEphemeralKey !== undefined)
|
||||||
|
privKeyQueue.push(data.ourEphemeralKey);
|
||||||
|
|
||||||
|
if (data.ourIdentityKey !== undefined)
|
||||||
|
return axolotl.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
|
||||||
|
axolotl.api.storage.put("25519KeyidentityKey", keyPair);
|
||||||
|
return postLocalKeySetup();
|
||||||
|
});
|
||||||
|
else
|
||||||
|
return postLocalKeySetup();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return doStep().then(stepDone);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("test vectors", function() {
|
||||||
|
function defineTest(i) {
|
||||||
|
it(axolotlTestVectors[i].name, function(done) {
|
||||||
|
localStorage.clear();
|
||||||
|
testSessionMap = {};
|
||||||
|
return runAxolotlTest(axolotlTestVectors[i].vectors).then(function(res) {
|
||||||
|
assert(res);
|
||||||
|
}).then(done).catch(done);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (var i in axolotlTestVectors)
|
||||||
|
defineTest(i);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
1
libaxolotl/test/protos
Symbolic link
1
libaxolotl/test/protos
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../protos/
|
85
libaxolotl/test/temp_helpers.js
Normal file
85
libaxolotl/test/temp_helpers.js
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
|
||||||
|
var StaticArrayBufferProto = new ArrayBuffer().__proto__;
|
||||||
|
var StaticUint8ArrayProto = new Uint8Array().__proto__;
|
||||||
|
function getString(thing) {
|
||||||
|
if (thing === Object(thing)) {
|
||||||
|
if (thing.__proto__ == StaticUint8ArrayProto)
|
||||||
|
return String.fromCharCode.apply(null, thing);
|
||||||
|
if (thing.__proto__ == StaticArrayBufferProto)
|
||||||
|
return getString(new Uint8Array(thing));
|
||||||
|
if (thing.__proto__ == StaticByteBufferProto)
|
||||||
|
return thing.toString("binary");
|
||||||
|
}
|
||||||
|
return thing;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStringable(thing) {
|
||||||
|
return (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean" ||
|
||||||
|
(thing === Object(thing) &&
|
||||||
|
(thing.__proto__ == StaticArrayBufferProto ||
|
||||||
|
thing.__proto__ == StaticUint8ArrayProto ||
|
||||||
|
thing.__proto__ == StaticByteBufferProto)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEqual(a, b, mayBeShort) {
|
||||||
|
// TODO: Special-case arraybuffers, etc
|
||||||
|
if (a === undefined || b === undefined)
|
||||||
|
return false;
|
||||||
|
a = getString(a);
|
||||||
|
b = getString(b);
|
||||||
|
var maxLength = mayBeShort ? Math.min(a.length, b.length) : Math.max(a.length, b.length);
|
||||||
|
if (maxLength < 5)
|
||||||
|
throw new Error("a/b compare too short");
|
||||||
|
return a.substring(0, Math.min(maxLength, a.length)) == b.substring(0, Math.min(maxLength, b.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArrayBuffer(thing) {
|
||||||
|
//TODO: Optimize this for specific cases
|
||||||
|
if (thing === undefined)
|
||||||
|
return undefined;
|
||||||
|
if (thing === Object(thing) && thing.__proto__ == StaticArrayBufferProto)
|
||||||
|
return thing;
|
||||||
|
|
||||||
|
if (thing instanceof Array) {
|
||||||
|
// Assuming Uint16Array from curve25519
|
||||||
|
var res = new ArrayBuffer(thing.length * 2);
|
||||||
|
var uint = new Uint16Array(res);
|
||||||
|
for (var i = 0; i < thing.length; i++)
|
||||||
|
uint[i] = thing[i];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getStringable(thing))
|
||||||
|
throw new Error("Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer");
|
||||||
|
var str = getString(thing);
|
||||||
|
var res = new ArrayBuffer(str.length);
|
||||||
|
var uint = new Uint8Array(res);
|
||||||
|
for (var i = 0; i < str.length; i++)
|
||||||
|
uint[i] = str.charCodeAt(i);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureStringed(thing) {
|
||||||
|
if (getStringable(thing))
|
||||||
|
return getString(thing);
|
||||||
|
else if (thing instanceof Array) {
|
||||||
|
var res = [];
|
||||||
|
for (var i = 0; i < thing.length; i++)
|
||||||
|
res[i] = ensureStringed(thing[i]);
|
||||||
|
return res;
|
||||||
|
} else if (thing === Object(thing)) {
|
||||||
|
var res = {};
|
||||||
|
for (var key in thing)
|
||||||
|
res[key] = ensureStringed(thing[key]);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
throw new Error("unsure of how to jsonify object of type " + typeof thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.textsecure = {
|
||||||
|
utils: {
|
||||||
|
jsonThing: function(thing) {
|
||||||
|
return JSON.stringify(ensureStringed(thing));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -11,42 +11,42 @@ axolotlTestVectors = function() {
|
||||||
["sendMessage",
|
["sendMessage",
|
||||||
{
|
{
|
||||||
smsText: "A",
|
smsText: "A",
|
||||||
ourBaseKey: hexToArrayBuffer('08474c43256fb3bde899d899c3e997b24b94839c9f55a1f55ea671e7cdc55f5c'),
|
ourBaseKey: hexToArrayBuffer('2060fe31b041d28127ac35cbfe790e2a25f92d2e21eb2251690ae75e732f5c4d'),
|
||||||
ourEphemeralKey: hexToArrayBuffer('e0a18f35a04b7cfd246f72f3c7fe0fc3b000f5d11fe548e818775b7e9d93a94c'),
|
ourEphemeralKey: hexToArrayBuffer('082e6391deb7154bd0375df3fc07f87020a3b0fd7a8c6c90e73f0e054bc2bf5d'),
|
||||||
ourIdentityKey: hexToArrayBuffer('a0f1dcf3d76ce4b538684b3360039bfde3ce59bca74449a01276e3ec395f4060'),
|
ourIdentityKey: hexToArrayBuffer('d83d8141aad5f1d62d78a1af09ffbe61f2d3458eeb887a047a58a07565d24463'),
|
||||||
registrationId: 9784,
|
registrationId: 10290,
|
||||||
getKeys: {identityKey: hexToArrayBuffer('05c7214f5c39c83ddf81c4d56e88a33285c95db5eb87eac67536003530f5d62628'),
|
getKeys: {identityKey: hexToArrayBuffer('059c2197be51bae703ae2edd26b6ff2b03d589ef4851be33a3f8d923ad86a6b439'),
|
||||||
devices: [{
|
devices: [{
|
||||||
deviceId: 1,
|
deviceId: 1,
|
||||||
preKey: {keyId: 2803392, publicKey: hexToArrayBuffer('05a189dc5be02a35e32fafa5e8e4296ef74132e29d0033de26685f471301c80738')},
|
preKey: {keyId: 4611143, publicKey: hexToArrayBuffer('052cd5004a4c31dd7b89b7fc80cc3e62abcf9cf1af014c93ec4589f7ca3e79e65c')},
|
||||||
signedPreKey: {keyId: 15452175, publicKey: hexToArrayBuffer('05e59ff855c698d58a3ff0dd04a925ebe1deffe276df623ddd873fb934b7314413')},
|
signedPreKey: {keyId: 14983230, publicKey: hexToArrayBuffer('05a9ecf666ec55fc27988ecc417db0d62dd5e1fa751da1f7a2dd2eca0d14c8bd46'), signature: hexToArrayBuffer('0b46fdb238f1e2df7b28a94ba575e58b0aa1d377bb843602cc8c2a7cd33770fdd741f65a240f7c3086f00f31dc4f3b8ceeab498356f8d5e4bfe6f2dd3eeca98f')},
|
||||||
registrationId: 42
|
registrationId: 0xd00d
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
expectedCiphertext: hexToArrayBuffer('3308c08dab01122105d51a5f0d744180bf49d1b71b5d77a66db9664a4806d8470b99bed6311b7ed1681a210596857fd3566a584bb7ff0664df4d11cfdba8e1a445e0930a527b7b139c6a897322d301330a210577874cb60271862f343d52984224e2558f828f336d68bd14fa4aaf5a1692be7d1000180022a001fa2af5c8688440c0bc45121ae2f6b9c6d5b8cf00acfee0d1a45f9e7b245636e1fa63b3062e2a6a9cd8be9096c375b413f71c2bb18054738c8440d1aa52997899d8bcedee6a93f6a295bdaf488e81188a9c88c4e841eb772b3194576c52bd8ef8fcbc5c29545fa38d2213c84d088f9843307f45c3254927f97c6f0afca9737a00d09146284f8948bbe69c755e47e6e571887bf57959b228ba9c2418f7bfc780b7bf1adbffd96276f328b84c308f90af07'),
|
expectedCiphertext: hexToArrayBuffer('3308c7b899021221058a49fa8a94224aaa8f5873404e01710ff9ef02169a75f90af4fbbc600796e0521a21050a6cf5e075c9970f14862db8a703a6c761f50b5182d17874908940556a22372222d301330a2105883ab58b3eb6db93b32bf91899a5b5175e7b21e96fff2cec02c83dff16ba1b271000180022a0013c5d070d1b75c418cef769bd7378a58969537a00e0ff60cbb99defb486fcfb43384264da4ea9821c1336f02d988da38944453331c4b30181704cbcec5a792ab87c5ccff256e0b4d61ba6a30a6964783875018882e66bfbd9445ac44fee9dc67edc2ad9de78adbe0eb7e9cb990272183ce5fac682ee5106f67d732cd16dfb731239590ba67dc827e849c49a9fb5ed8eed41d85d5e6de3294e74f3524c6489c2f25482ff52f9ea29c928b25030bec09207'),
|
||||||
}],
|
}],
|
||||||
["sendMessage",
|
["sendMessage",
|
||||||
{
|
{
|
||||||
smsText: "B",
|
smsText: "B",
|
||||||
expectedCiphertext: hexToArrayBuffer('3308c08dab01122105d51a5f0d744180bf49d1b71b5d77a66db9664a4806d8470b99bed6311b7ed1681a210596857fd3566a584bb7ff0664df4d11cfdba8e1a445e0930a527b7b139c6a897322d301330a210577874cb60271862f343d52984224e2558f828f336d68bd14fa4aaf5a1692be7d1001180022a00138b6a0e9b02bd7347e7428cc443df228b7a58a28456812d0f100985937ac08cf729f8be6a38596d3611c035352845f9732901a42e3dd4761be43d231edba5a56bcd60f3534e8872816a1c9eed4383ec0cb958ce2e66f00f8e5c90c13ebe44af5516df5cb41dfb74818795881633e19fefe562d3e89013aafba0aa672dab3e418b02f3a5c4c28d1be1a47bf3a79a95cccf071debe38a093dab22027296bfb0caa892317d15c715b8c28b84c308f90af07'),
|
expectedCiphertext: hexToArrayBuffer('3308c7b899021221058a49fa8a94224aaa8f5873404e01710ff9ef02169a75f90af4fbbc600796e0521a21050a6cf5e075c9970f14862db8a703a6c761f50b5182d17874908940556a22372222d301330a2105883ab58b3eb6db93b32bf91899a5b5175e7b21e96fff2cec02c83dff16ba1b271001180022a001256aae85babf8c0808f75e08bf10a63f7f3aea97324c2583d777f609df493d7d45232c8883c3e1118fbc29b6318a3091ae57fed4f1c54458c6bb832fbb35f24933cb79765d00f4a161e2877a5a21a26592cdb0aa8a2f70f5fbe8c601ecdff0bef1b733d7fd0cb7b7d8fc1e45f79c016c8f90449239ca1a04b374538f2760eef43127ddc9a6439c6ceca5faf5962fb26d7248257d4d5ee3fe4cf8795acc555718558e5317f618828328b25030bec09207'),
|
||||||
}],
|
}],
|
||||||
["receiveMessage",
|
["receiveMessage",
|
||||||
{
|
{
|
||||||
message: hexToArrayBuffer('330a210519549798b47a051f48291f03140179329c03de0243459c5283d7b31d65b3ec661000180022a001dce182f136cc10858ecb48cd3299882de15006b179626f13d85f9353f64782df6afafefee527bab4ad7aedeb5863fdd0641d3db8bed305b4b64df6d1d39fa262058066430ea1fdd019b76cfcef4ae412214dd37f5a3e4270d48e278455fe94e2bd99940ec562703e45bbeab9a0a147e6e66af6b8188cb8bf7eaf18d601eb7637055e5528afce2e4a48ac49915a15aa23750f24644777a4c609f0f2fb4cbe93934dc8144f2ea3c888'),
|
message: hexToArrayBuffer('330a2105bc81f1348a1d065b2bd2776edb9f29bc4150399db35c1d87dc258b94894bc57a1000180022a001c93af1107634d9eaa1516a4f8e95c6a454c27313b38830709eb863608f08f2f3a598ff8f558645427f7b6ea8e182e40f7b4a92ce0325f2e22f76f36f6954f6f391dd21d2cad12e5b620e75b991e69df8821ab0e826e3cb2ae1c7a1fb8ed72213e36fc508ca1f0a92ebe2089535b5d5e1b34eae5f91497bd072de47de3291ba78a6fd67d3f8f3f20d04ab3a1159df8f36ef7e4696847e32ce6be07edb93763a2226c87feff8cc4827'),
|
||||||
type: 1,
|
type: 1,
|
||||||
newEphemeralKey: hexToArrayBuffer('d872c0de95e128656ddb3a2ac422ab9c5273415f6e55996a5dd395f915472052'),
|
newEphemeralKey: hexToArrayBuffer('d04f334799ea1272eff64c5267e28274f54b91b3b11372879303eb7a8cd52763'),
|
||||||
expectedSmsText: "C",
|
expectedSmsText: "C",
|
||||||
}],
|
}],
|
||||||
["receiveMessage",
|
["receiveMessage",
|
||||||
{
|
{
|
||||||
message: hexToArrayBuffer('330a210519549798b47a051f48291f03140179329c03de0243459c5283d7b31d65b3ec661001180022a0014428b3743a7be1682237400d3997a6ccccc7aecbed3192d819e05b5dad8bd91d3ca1fcb39a6187a8c9fe1e0216f37aecb0178cf0f2998a1177e611f0f0ab18a1d528541eda02137a45b388377a13387e65c4bbdd468fa2da77e4de567828914225de8d27ed62e05d2da32b9ae19ac37cf903990973eef8616d58ab2b67848526244980f3827aee4e56d715500adac8f6d93fd8dd24d00a3a3e001a1f4b86049195f2d93815efd3f3'),
|
message: hexToArrayBuffer('330a2105bc81f1348a1d065b2bd2776edb9f29bc4150399db35c1d87dc258b94894bc57a1001180022a001eb52c72c7bb6b8878c96398cc05810382d29fc17644f88bdc8d57509e8a734626620ae243cb740466806ee3c64bbf12957d5ac0452a17aba6c0e10e2a82626a986df0c4e5cadebb9ce824f1af4fac85cf7d1b9b7cf37f5df06d77b901d0e2aaa772b49f838ec92a67d13b4d7908cf91f7e0a54ad031b2aa4a954180b652f0696350e4f286592e24cc83091b196f2d48397241e33acaf6f65be27af12f1a8af91fd1daf2c01bdfaaa'),
|
||||||
type: 1,
|
type: 1,
|
||||||
expectedSmsText: "D",
|
expectedSmsText: "D",
|
||||||
}],
|
}],
|
||||||
["sendMessage",
|
["sendMessage",
|
||||||
{
|
{
|
||||||
smsText: "E",
|
smsText: "E",
|
||||||
expectedCiphertext: hexToArrayBuffer('330a21052f7f7ab6e0d172b8fcab6f7e4b7adef1dc25205d3642e665f11f5681798d99451000180122a001e492d8b25eaec22f39ff1c8cac2e8ac164d0ebb5894c20330e20ebce6dc58ea0469b3e0075657eebc6e04c1da3aed6d8ab7631412a017cc20bf18b433d2ead4fd40320e9093b8be5565d581fd679a3c296edeb463638353422ead082239f7047537c79a749d4949e3a21d98ec873506d27c5f1abea28d2faddd1f5d4e26c1633eaa213af5372daf8d76308097d54a97cee1164f2302784f21f6808d031a5650f8598069de06473b1'),
|
expectedCiphertext: hexToArrayBuffer('330a2105576f3c29717db75ffd19a37154d4d6beba8d796a26c4244793132f7e6cb180491000180122a001bd139a95021d34d9df74d99aa897981aa6718fd6b72d8567891afff92c6e3534ded0de80be7e7c58730a001f2acc1f1e6447f9ca0a99681f3f65d9a4072f3a1fb978740918d3db5c346170edb3bf8fec2b52362edf7138f93cb23a3f17b0f40bf9769e01273955b14c20b6212cbb1f665d1a7e5e770437a53b1727c13bcd639bf5beba71893b8de435244acddc42c3ba592b7debdacdc4dea12dc7e4e670753419be0455e0043f91'),
|
||||||
}],
|
}],
|
||||||
];
|
];
|
||||||
// Now change the order and make 2 tests out of them:
|
// Now change the order and make 2 tests out of them:
|
||||||
|
@ -73,37 +73,37 @@ axolotlTestVectors = function() {
|
||||||
var axolotlTwoPartyTestVectorsBob = [
|
var axolotlTwoPartyTestVectorsBob = [
|
||||||
["receiveMessage",
|
["receiveMessage",
|
||||||
{
|
{
|
||||||
message: hexToArrayBuffer('3308c08dab01122105d51a5f0d744180bf49d1b71b5d77a66db9664a4806d8470b99bed6311b7ed1681a210596857fd3566a584bb7ff0664df4d11cfdba8e1a445e0930a527b7b139c6a897322d301330a210577874cb60271862f343d52984224e2558f828f336d68bd14fa4aaf5a1692be7d1000180022a001fa2af5c8688440c0bc45121ae2f6b9c6d5b8cf00acfee0d1a45f9e7b245636e1fa63b3062e2a6a9cd8be9096c375b413f71c2bb18054738c8440d1aa52997899d8bcedee6a93f6a295bdaf488e81188a9c88c4e841eb772b3194576c52bd8ef8fcbc5c29545fa38d2213c84d088f9843307f45c3254927f97c6f0afca9737a00d09146284f8948bbe69c755e47e6e571887bf57959b228ba9c2418f7bfc780b7bf1adbffd96276f328b84c308f90af07'),
|
message: hexToArrayBuffer('3308c7b899021221058a49fa8a94224aaa8f5873404e01710ff9ef02169a75f90af4fbbc600796e0521a21050a6cf5e075c9970f14862db8a703a6c761f50b5182d17874908940556a22372222d301330a2105883ab58b3eb6db93b32bf91899a5b5175e7b21e96fff2cec02c83dff16ba1b271000180022a0013c5d070d1b75c418cef769bd7378a58969537a00e0ff60cbb99defb486fcfb43384264da4ea9821c1336f02d988da38944453331c4b30181704cbcec5a792ab87c5ccff256e0b4d61ba6a30a6964783875018882e66bfbd9445ac44fee9dc67edc2ad9de78adbe0eb7e9cb990272183ce5fac682ee5106f67d732cd16dfb731239590ba67dc827e849c49a9fb5ed8eed41d85d5e6de3294e74f3524c6489c2f25482ff52f9ea29c928b25030bec09207'),
|
||||||
type: 3,
|
type: 3,
|
||||||
ourPreKey: hexToArrayBuffer('40a5ce4c6e21c2e686bed765c854b010117ea26fb08438994d84ffa516c7d84e'),
|
ourPreKey: hexToArrayBuffer('88d9a12e7b03afdac42e49ec9d4e5488e1b1e6d48c6eef6029e45dec09a9d562'),
|
||||||
preKeyId: 2803392,
|
preKeyId: 4611143,
|
||||||
ourSignedPreKey: hexToArrayBuffer('280d9e0067b68c877c48120d400f5a16c0b3e74374149751777d1f3c49b2b355'),
|
ourSignedPreKey: hexToArrayBuffer('888b3f14aff80e36bb2d2cc26a72da2e1a99330962f5066c7c1dded1262ca665'),
|
||||||
signedPreKeyId: 15452175,
|
signedPreKeyId: 14983230,
|
||||||
ourIdentityKey: hexToArrayBuffer('b8ee332fd87c5544ccd52afa8ce55140b25fd4ca4441a232799fe474ff4cae79'),
|
ourIdentityKey: hexToArrayBuffer('58c9fb2ec2c6b13e279e7db57ce837c02aac1531504f71130d167cc8fb25a857'),
|
||||||
newEphemeralKey: hexToArrayBuffer('400146d280077821aacaed96ad75b99ab665d2530ef5c061fad0e24bac285640'),
|
newEphemeralKey: hexToArrayBuffer('f0b66ac79b6f4ae997636bc8ed622a184dbe00603b2c657ac18800122523d142'),
|
||||||
expectedSmsText: "A",
|
expectedSmsText: "A",
|
||||||
}],
|
}],
|
||||||
["receiveMessage",
|
["receiveMessage",
|
||||||
{
|
{
|
||||||
message: hexToArrayBuffer('3308c08dab01122105d51a5f0d744180bf49d1b71b5d77a66db9664a4806d8470b99bed6311b7ed1681a210596857fd3566a584bb7ff0664df4d11cfdba8e1a445e0930a527b7b139c6a897322d301330a210577874cb60271862f343d52984224e2558f828f336d68bd14fa4aaf5a1692be7d1001180022a00138b6a0e9b02bd7347e7428cc443df228b7a58a28456812d0f100985937ac08cf729f8be6a38596d3611c035352845f9732901a42e3dd4761be43d231edba5a56bcd60f3534e8872816a1c9eed4383ec0cb958ce2e66f00f8e5c90c13ebe44af5516df5cb41dfb74818795881633e19fefe562d3e89013aafba0aa672dab3e418b02f3a5c4c28d1be1a47bf3a79a95cccf071debe38a093dab22027296bfb0caa892317d15c715b8c28b84c308f90af07'),
|
message: hexToArrayBuffer('3308c7b899021221058a49fa8a94224aaa8f5873404e01710ff9ef02169a75f90af4fbbc600796e0521a21050a6cf5e075c9970f14862db8a703a6c761f50b5182d17874908940556a22372222d301330a2105883ab58b3eb6db93b32bf91899a5b5175e7b21e96fff2cec02c83dff16ba1b271001180022a001256aae85babf8c0808f75e08bf10a63f7f3aea97324c2583d777f609df493d7d45232c8883c3e1118fbc29b6318a3091ae57fed4f1c54458c6bb832fbb35f24933cb79765d00f4a161e2877a5a21a26592cdb0aa8a2f70f5fbe8c601ecdff0bef1b733d7fd0cb7b7d8fc1e45f79c016c8f90449239ca1a04b374538f2760eef43127ddc9a6439c6ceca5faf5962fb26d7248257d4d5ee3fe4cf8795acc555718558e5317f618828328b25030bec09207'),
|
||||||
type: 3,
|
type: 3,
|
||||||
expectedSmsText: "B",
|
expectedSmsText: "B",
|
||||||
}],
|
}],
|
||||||
["sendMessage",
|
["sendMessage",
|
||||||
{
|
{
|
||||||
smsText: "C",
|
smsText: "C",
|
||||||
expectedCiphertext: hexToArrayBuffer('330a210519549798b47a051f48291f03140179329c03de0243459c5283d7b31d65b3ec661000180022a001dce182f136cc10858ecb48cd3299882de15006b179626f13d85f9353f64782df6afafefee527bab4ad7aedeb5863fdd0641d3db8bed305b4b64df6d1d39fa262058066430ea1fdd019b76cfcef4ae412214dd37f5a3e4270d48e278455fe94e2bd99940ec562703e45bbeab9a0a147e6e66af6b8188cb8bf7eaf18d601eb7637055e5528afce2e4a48ac49915a15aa23750f24644777a4c609f0f2fb4cbe93934dc8144f2ea3c888'),
|
expectedCiphertext: hexToArrayBuffer('330a2105bc81f1348a1d065b2bd2776edb9f29bc4150399db35c1d87dc258b94894bc57a1000180022a001c93af1107634d9eaa1516a4f8e95c6a454c27313b38830709eb863608f08f2f3a598ff8f558645427f7b6ea8e182e40f7b4a92ce0325f2e22f76f36f6954f6f391dd21d2cad12e5b620e75b991e69df8821ab0e826e3cb2ae1c7a1fb8ed72213e36fc508ca1f0a92ebe2089535b5d5e1b34eae5f91497bd072de47de3291ba78a6fd67d3f8f3f20d04ab3a1159df8f36ef7e4696847e32ce6be07edb93763a2226c87feff8cc4827'),
|
||||||
}],
|
}],
|
||||||
["sendMessage",
|
["sendMessage",
|
||||||
{
|
{
|
||||||
smsText: "D",
|
smsText: "D",
|
||||||
expectedCiphertext: hexToArrayBuffer('330a210519549798b47a051f48291f03140179329c03de0243459c5283d7b31d65b3ec661001180022a0014428b3743a7be1682237400d3997a6ccccc7aecbed3192d819e05b5dad8bd91d3ca1fcb39a6187a8c9fe1e0216f37aecb0178cf0f2998a1177e611f0f0ab18a1d528541eda02137a45b388377a13387e65c4bbdd468fa2da77e4de567828914225de8d27ed62e05d2da32b9ae19ac37cf903990973eef8616d58ab2b67848526244980f3827aee4e56d715500adac8f6d93fd8dd24d00a3a3e001a1f4b86049195f2d93815efd3f3'),
|
expectedCiphertext: hexToArrayBuffer('330a2105bc81f1348a1d065b2bd2776edb9f29bc4150399db35c1d87dc258b94894bc57a1001180022a001eb52c72c7bb6b8878c96398cc05810382d29fc17644f88bdc8d57509e8a734626620ae243cb740466806ee3c64bbf12957d5ac0452a17aba6c0e10e2a82626a986df0c4e5cadebb9ce824f1af4fac85cf7d1b9b7cf37f5df06d77b901d0e2aaa772b49f838ec92a67d13b4d7908cf91f7e0a54ad031b2aa4a954180b652f0696350e4f286592e24cc83091b196f2d48397241e33acaf6f65be27af12f1a8af91fd1daf2c01bdfaaa'),
|
||||||
}],
|
}],
|
||||||
["receiveMessage",
|
["receiveMessage",
|
||||||
{
|
{
|
||||||
message: hexToArrayBuffer('330a21052f7f7ab6e0d172b8fcab6f7e4b7adef1dc25205d3642e665f11f5681798d99451000180122a001e492d8b25eaec22f39ff1c8cac2e8ac164d0ebb5894c20330e20ebce6dc58ea0469b3e0075657eebc6e04c1da3aed6d8ab7631412a017cc20bf18b433d2ead4fd40320e9093b8be5565d581fd679a3c296edeb463638353422ead082239f7047537c79a749d4949e3a21d98ec873506d27c5f1abea28d2faddd1f5d4e26c1633eaa213af5372daf8d76308097d54a97cee1164f2302784f21f6808d031a5650f8598069de06473b1'),
|
message: hexToArrayBuffer('330a2105576f3c29717db75ffd19a37154d4d6beba8d796a26c4244793132f7e6cb180491000180122a001bd139a95021d34d9df74d99aa897981aa6718fd6b72d8567891afff92c6e3534ded0de80be7e7c58730a001f2acc1f1e6447f9ca0a99681f3f65d9a4072f3a1fb978740918d3db5c346170edb3bf8fec2b52362edf7138f93cb23a3f17b0f40bf9769e01273955b14c20b6212cbb1f665d1a7e5e770437a53b1727c13bcd639bf5beba71893b8de435244acddc42c3ba592b7debdacdc4dea12dc7e4e670753419be0455e0043f91'),
|
||||||
type: 1,
|
type: 1,
|
||||||
newEphemeralKey: hexToArrayBuffer('b89a87781558e4e9d19ebefa103c1ccdb20b573678f0753500376decfa975e71'),
|
newEphemeralKey: hexToArrayBuffer('98bee5f861b528816888d45c2ca40125b111d2c03e483e57e6886c82dd758467'),
|
||||||
expectedSmsText: "E",
|
expectedSmsText: "E",
|
||||||
}],
|
}],
|
||||||
];
|
];
|
||||||
|
@ -466,6 +466,7 @@ axolotlTestVectors = function() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: GROUPS
|
//TODO: GROUPS
|
||||||
|
//TODO: Sender changes identity key?
|
||||||
|
|
||||||
return tests;
|
return tests;
|
||||||
}();
|
}();
|
|
@ -46,7 +46,6 @@
|
||||||
<script type="text/javascript" src="../sendmessage.js" data-cover></script>
|
<script type="text/javascript" src="../sendmessage.js" data-cover></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="fake_api.js"></script>
|
<script type="text/javascript" src="fake_api.js"></script>
|
||||||
<script type="text/javascript" src="testvectors.js"></script>
|
|
||||||
<script type="text/javascript" src="helpers_test.js"></script>
|
<script type="text/javascript" src="helpers_test.js"></script>
|
||||||
<script type="text/javascript" src="websocket-resources_test.js"></script>
|
<script type="text/javascript" src="websocket-resources_test.js"></script>
|
||||||
<script type="text/javascript" src="protocol_test.js"></script>
|
<script type="text/javascript" src="protocol_test.js"></script>
|
||||||
|
|
|
@ -40,193 +40,5 @@ describe('Protocol', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Use fake_api's hiding of api.sendMessage to test sendmessage.js' maze
|
||||||
describe("Identity and Pre Key Creation", function() {
|
|
||||||
this.timeout(200000);
|
|
||||||
before(function() { localStorage.clear(); });
|
|
||||||
after(function() { localStorage.clear(); });
|
|
||||||
it ('works', function(done) {
|
|
||||||
localStorage.clear();
|
|
||||||
return axolotl.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 axolotl.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 axolotl.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 origCreateKeyPair = axolotl.crypto.createKeyPair;
|
|
||||||
var doStep;
|
|
||||||
var stepDone;
|
|
||||||
|
|
||||||
stepDone = function(res) {
|
|
||||||
if (!res || privKeyQueue.length != 0 || Object.keys(getKeysForNumberMap).length != 0 || Object.keys(messagesSentMap).length != 0) {
|
|
||||||
axolotl.crypto.createKeyPair = origCreateKeyPair;
|
|
||||||
return false;
|
|
||||||
} else if (step == v.length) {
|
|
||||||
axolotl.crypto.createKeyPair = origCreateKeyPair;
|
|
||||||
return true;
|
|
||||||
} else
|
|
||||||
return doStep().then(stepDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
var privKeyQueue = [];
|
|
||||||
axolotl.crypto.createKeyPair = function(privKey) {
|
|
||||||
if (privKey !== undefined)
|
|
||||||
return origCreateKeyPair(privKey);
|
|
||||||
if (privKeyQueue.length == 0)
|
|
||||||
throw new Error('Out of private keys');
|
|
||||||
else {
|
|
||||||
var privKey = privKeyQueue.shift();
|
|
||||||
return axolotl.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_wrapper.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 axolotl.crypto.createKeyPair(data.ourIdentityKey).then(function(keyPair) {
|
|
||||||
textsecure.storage.putEncrypted("25519KeyidentityKey", keyPair);
|
|
||||||
return axolotl.crypto.createKeyPair(data.ourSignedPreKey).then(function(keyPair) {
|
|
||||||
textsecure.storage.putEncrypted("25519KeysignedKey" + data.signedPreKeyId, keyPair);
|
|
||||||
|
|
||||||
if (data.ourPreKey !== undefined)
|
|
||||||
return axolotl.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 = axolotl.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 = axolotl.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, [], Date.now()).then(checkMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.ourBaseKey !== undefined)
|
|
||||||
privKeyQueue.push(data.ourBaseKey);
|
|
||||||
if (data.ourEphemeralKey !== undefined)
|
|
||||||
privKeyQueue.push(data.ourEphemeralKey);
|
|
||||||
|
|
||||||
if (data.ourIdentityKey !== undefined)
|
|
||||||
return axolotl.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() {
|
|
||||||
for (var i in axolotlTestVectors) {
|
|
||||||
it(axolotlTestVectors[i].name, function(done) {
|
|
||||||
localStorage.clear();
|
|
||||||
return runAxolotlTest(axolotlTestVectors[i].vectors).then(function(res) {
|
|
||||||
assert(res);
|
|
||||||
}).then(done).catch(done);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue