|
|
@ -537,7 +537,7 @@ var crypto_tests = {};
|
|
|
|
/******************************
|
|
|
|
/******************************
|
|
|
|
*** Ratchet implementation ***
|
|
|
|
*** Ratchet implementation ***
|
|
|
|
******************************/
|
|
|
|
******************************/
|
|
|
|
var initSession = function(isInitiator, theirIdentityPubKey, ourEphemeralPrivKey, theirEphemeralPubKey, callback) {
|
|
|
|
var initSession = function(isInitiator, ourEphemeralKey, encodedNumber, theirIdentityPubKey, theirEphemeralPubKey, callback) {
|
|
|
|
var ourIdentityPrivKey = crypto_storage.getIdentityPrivKey();
|
|
|
|
var ourIdentityPrivKey = crypto_storage.getIdentityPrivKey();
|
|
|
|
|
|
|
|
|
|
|
|
var sharedSecret;
|
|
|
|
var sharedSecret;
|
|
|
@ -545,21 +545,30 @@ var crypto_tests = {};
|
|
|
|
sharedSecret = getString(ecRes);
|
|
|
|
sharedSecret = getString(ecRes);
|
|
|
|
|
|
|
|
|
|
|
|
function finishInit() {
|
|
|
|
function finishInit() {
|
|
|
|
ECDHE(theirEphemeralPubKey, ourEphemeralPrivKey, function(ecRes) {
|
|
|
|
ECDHE(theirEphemeralPubKey, ourEphemeralKey.privKey, function(ecRes) {
|
|
|
|
sharedSecret += getString(ecRes);
|
|
|
|
sharedSecret += getString(ecRes);
|
|
|
|
|
|
|
|
|
|
|
|
var masterKey = HKDF(sharedSecret, '', "WhisperText");
|
|
|
|
var masterKey = HKDF(sharedSecret, '', "WhisperText");
|
|
|
|
callback({ rootKey: masterKey[0], chainKey: masterKey[1] });
|
|
|
|
|
|
|
|
|
|
|
|
var session = {currentRatchet: { rootKey: masterKey[0], ephemeralKeyPair: ourEphemeralKey,
|
|
|
|
|
|
|
|
lastRemoteEphemeralKey: theirEphemeralPubKey },
|
|
|
|
|
|
|
|
oldRatchetList: []
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
session[getString(ourEphemeralKey.pubKey)] = { messageKeys: {}, chainKey: { counter: -1, key: masterKey[1] } };
|
|
|
|
|
|
|
|
// This isnt an actual ratchet, its just here to make maybeStepRatchet work
|
|
|
|
|
|
|
|
session[getString(theirEphemeralPubKey)] = { messageKeys: {}, chainKey: { counter: 0xffffffff, key: '' } };
|
|
|
|
|
|
|
|
crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (isInitiator) {
|
|
|
|
if (isInitiator) {
|
|
|
|
ECDHE(theirIdentityPubKey, ourEphemeralPrivKey, function(ecRes) {
|
|
|
|
ECDHE(theirIdentityPubKey, ourEphemeralKey.privKey, function(ecRes) {
|
|
|
|
sharedSecret = sharedSecret + getString(ecRes);
|
|
|
|
sharedSecret = sharedSecret + getString(ecRes);
|
|
|
|
finishInit();
|
|
|
|
finishInit();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ECDHE(theirIdentityPubKey, ourEphemeralPrivKey, function(ecRes) {
|
|
|
|
ECDHE(theirIdentityPubKey, ourEphemeralKey.privKey, function(ecRes) {
|
|
|
|
sharedSecret = getString(ecRes) + sharedSecret;
|
|
|
|
sharedSecret = getString(ecRes) + sharedSecret;
|
|
|
|
finishInit();
|
|
|
|
finishInit();
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -574,16 +583,7 @@ var crypto_tests = {};
|
|
|
|
if (preKeyPair === undefined)
|
|
|
|
if (preKeyPair === undefined)
|
|
|
|
throw "Missing preKey for PreKeyWhisperMessage";
|
|
|
|
throw "Missing preKey for PreKeyWhisperMessage";
|
|
|
|
|
|
|
|
|
|
|
|
initSession(false, message.identityKey, preKeyPair.privKey, message.baseKey, function(firstRatchet) {
|
|
|
|
initSession(false, preKeyPair, encodedNumber, message.identityKey, message.baseKey, function() {
|
|
|
|
var session = {currentRatchet: { rootKey: firstRatchet.rootKey, ephemeralKeyPair: preKeyPair,
|
|
|
|
|
|
|
|
lastRemoteEphemeralKey: message.baseKey },
|
|
|
|
|
|
|
|
oldRatchetList: []
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
session[getString(preKeyPair.pubKey)] = { messageKeys: {}, chainKey: { counter: -1, key: firstRatchet.chainKey } };
|
|
|
|
|
|
|
|
// This isnt an actual ratchet, its just here to make maybeStepRatchet work
|
|
|
|
|
|
|
|
session[getString(message.baseKey)] = { messageKeys: {}, chainKey: { counter: 0xffffffff, key: '' } };
|
|
|
|
|
|
|
|
crypto_storage.saveSession(encodedNumber, session);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
callback();
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -633,14 +633,6 @@ var crypto_tests = {};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var doDecryptWhisperMessage = function(ciphertext, mac, messageKey, counter) {
|
|
|
|
|
|
|
|
//TODO keys swapped?
|
|
|
|
|
|
|
|
var keys = HKDF(messageKey, '', "WhisperMessageKeys");
|
|
|
|
|
|
|
|
verifyMACWithVersionByte(ciphertext, keys[0], mac);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return AES_CTR_NOPADDING(keys[1], CTR = counter, ciphertext);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// returns decrypted protobuf
|
|
|
|
// returns decrypted protobuf
|
|
|
|
var decryptWhisperMessage = function(encodedNumber, messageBytes, callback) {
|
|
|
|
var decryptWhisperMessage = function(encodedNumber, messageBytes, callback) {
|
|
|
|
var session = crypto_storage.getSession(encodedNumber);
|
|
|
|
var session = crypto_storage.getSession(encodedNumber);
|
|
|
@ -715,9 +707,34 @@ var crypto_tests = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
crypto.encryptMessageFor = function(deviceObject, message) {
|
|
|
|
// callback(encoded [PreKey]WhisperMessage)
|
|
|
|
return message + " encrypted to " + deviceObject.encodedNumber + " with relay " + deviceObject.relay +
|
|
|
|
crypto.encryptMessageFor = function(deviceObject, pushMessageContent, callback) {
|
|
|
|
" with identityKey " + deviceObject.identityKey + " and public key " + deviceObject.publicKey; //TODO
|
|
|
|
var session = crypto_storage.getSession(deviceObject.encodedNumber);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var doEncryptPushMessageContent = function(callback) {
|
|
|
|
|
|
|
|
var msg = new WhisperMessageProtobuf();
|
|
|
|
|
|
|
|
var plaintext = pushMessageContent.encode();
|
|
|
|
|
|
|
|
//TODO
|
|
|
|
|
|
|
|
msg.ciphertext = plaintext;//TODO: WAT?
|
|
|
|
|
|
|
|
callback(msg.encode());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (session === undefined) {
|
|
|
|
|
|
|
|
var preKeyMsg = new PreKeyWhisperMessageProtobuf();
|
|
|
|
|
|
|
|
preKeyMsg.identityKey = getString(crypto_storage.getStoredPubKey("identityKey"));
|
|
|
|
|
|
|
|
createNewKeyPair(function(baseKey) {
|
|
|
|
|
|
|
|
preKeyMsg.baseKey = getString(baseKey.pubKey);
|
|
|
|
|
|
|
|
preKeyMsg.preKeyId = preKey.keyId;
|
|
|
|
|
|
|
|
initSession();//TODO
|
|
|
|
|
|
|
|
doEncryptPushMessageContent(function(message) {
|
|
|
|
|
|
|
|
preKeyMsg.message = getString(message);
|
|
|
|
|
|
|
|
callback(getString(preKeyMsg.encode()));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
doEncryptPushMessageContent(function(message) {
|
|
|
|
|
|
|
|
callback(getString(message));
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var GENERATE_KEYS_KEYS_GENERATED = 100;
|
|
|
|
var GENERATE_KEYS_KEYS_GENERATED = 100;
|
|
|
|