Update libsignal-protocol v0.8.0

Reorder identity key check
This commit is contained in:
lilia 2016-05-02 16:55:02 -07:00
parent eee93987f8
commit 213b44935d
2 changed files with 134 additions and 138 deletions

View file

@ -34020,7 +34020,7 @@ Curve25519Worker.prototype = {
*/
var Internal = Internal || {};
Internal.crypto = function() {
(function() {
'use strict';
var crypto = window.crypto;
@ -34041,7 +34041,7 @@ Internal.crypto = function() {
}
};
return {
Internal.crypto = {
getRandomBytes: function(size) {
var array = new Uint8Array(size);
crypto.getRandomValues(array);
@ -34138,7 +34138,16 @@ Internal.crypto = function() {
return Internal.curve25519.verify(pubKey, msg, sig);
}
};
}();
// HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes
Internal.HKDF = function(input, salt, info) {
if (salt.byteLength != 32)
throw new Error("Got salt of incorrect length");
return Internal.crypto.HKDF(input, salt, util.toArrayBuffer(info));
}
})();
/* vim: ts=4:sw=4
*
@ -34270,17 +34279,6 @@ window.libsignal = window.libsignal || {};
libsignal.protocol = function() {
var self = {};
/*****************************
*** Internal Crypto stuff ***
*****************************/
Internal.HKDF = function(input, salt, info) {
// HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes
if (salt.byteLength != 32)
throw new Error("Got salt of incorrect length");
return Internal.crypto.HKDF(input, salt, util.toArrayBuffer(info));
}
var verifyMAC = function(data, key, mac, length) {
return Internal.crypto.sign(key, data).then(function(calculated_mac) {
if (mac.byteLength != length || calculated_mac.byteLength < length) {
@ -34301,27 +34299,6 @@ libsignal.protocol = function() {
/******************************
*** Ratchet implementation ***
******************************/
Internal.calculateRatchet = function(session, remoteKey, sending) {
var ratchet = session.currentRatchet;
return Internal.crypto.ECDHE(remoteKey, util.toArrayBuffer(ratchet.ephemeralKeyPair.privKey)).then(function(sharedSecret) {
return Internal.HKDF(sharedSecret, util.toArrayBuffer(ratchet.rootKey), "WhisperRatchet").then(function(masterKey) {
var ephemeralPublicKey;
if (sending) {
ephemeralPublicKey = ratchet.ephemeralKeyPair.pubKey;
}
else {
ephemeralPublicKey = remoteKey;
}
session[util.toString(ephemeralPublicKey)] = {
messageKeys: {},
chainKey: { counter: -1, key: masterKey[1] }
};
ratchet.rootKey = masterKey[0];
});
});
}
self.createIdentityKeyRecvSocket = function() {
var socketInfo = {};
var keyPair;
@ -34613,10 +34590,12 @@ Internal.SessionRecord = function() {
haveOpenSession: function() {
return this.registrationId !== null;
},
getSessionOrIdentityKeyByBaseKey: function(baseKey) {
var sessions = this._sessions;
var preferredSession = this._sessions[util.toString(baseKey)];
getSessionByBaseKey: function(baseKey) {
return this._sessions[util.toString(baseKey)];
},
getSessionOrIdentityKeyByBaseKey: function(baseKey) {
var preferredSession = this.getSessionByBaseKey(baseKey);
if (preferredSession !== undefined) {
return preferredSession;
}
@ -34867,15 +34846,31 @@ SessionBuilder.prototype = {
}.bind(this));
},
processV3: function(record, message) {
var preKeyPair, signedPreKeyPair;
var session = record.getSessionOrIdentityKeyByBaseKey(message.baseKey);
return Promise.all([
this.storage.loadPreKey(message.preKeyId),
this.storage.loadSignedPreKey(message.signedPreKeyId),
]).then(function(results) {
preKeyPair = results[0];
signedPreKeyPair = results[1];
}).then(function() {
var preKeyPair, signedPreKeyPair, session;
return this.storage.isTrustedIdentity(
this.remoteAddress.getName(), message.identityKey.toArrayBuffer()
).then(function(trusted) {
if (!trusted) {
var e = new Error('Unknown identity key');
e.identityKey = message.identityKey.toArrayBuffer();
throw e;
}
return Promise.all([
this.storage.loadPreKey(message.preKeyId),
this.storage.loadSignedPreKey(message.signedPreKeyId),
]).then(function(results) {
preKeyPair = results[0];
signedPreKeyPair = results[1];
});
}.bind(this)).then(function() {
session = record.getSessionByBaseKey(message.baseKey);
if (session) {
console.log("Duplicate PreKeyMessage for session");
return;
}
session = record.getOpenSession();
if (signedPreKeyPair === undefined) {
// Session may or may not be the right one, but if its not, we
// can't do anything about it ...fall through and let
@ -34886,24 +34881,9 @@ SessionBuilder.prototype = {
throw new Error("Missing Signed PreKey for PreKeyWhisperMessage");
}
}
if (session !== undefined) {
// Duplicate PreKeyMessage for session:
if (util.isEqual(session.indexInfo.baseKey, message.baseKey)) {
return;
}
// We already had a session/known identity key:
if (util.isEqual(session.indexInfo.remoteIdentityKey, message.identityKey)) {
// If the identity key matches the previous one, close the
// previous one and use the new one
record.archiveCurrentState();
} else {
// ...otherwise create an error that the UI will pick up
// and ask the user if they want to re-negotiate
var e = new Error('Unknown identity key');
e.identityKey = message.identityKey.toArrayBuffer();
throw e;
}
if (session !== undefined) {
record.archiveCurrentState();
}
if (message.preKeyId && !preKeyPair) {
console.log('Invalid prekey id');
@ -34992,18 +34972,36 @@ SessionBuilder.prototype = {
session.indexInfo.baseKey = ourEphemeralKey.pubKey;
return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) {
session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey;
return Internal.calculateRatchet(session, theirSignedPubKey, true).then(function() {
return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() {
return session;
});
});
}.bind(this));
} else {
session.indexInfo.baseKey = theirEphemeralPubKey;
session.currentRatchet.ephemeralKeyPair = ourSignedKey;
return session;
}
});
});
}.bind(this));
}.bind(this));
},
calculateSendingRatchet: function(session, remoteKey) {
var ratchet = session.currentRatchet;
return Internal.crypto.ECDHE(
remoteKey, util.toArrayBuffer(ratchet.ephemeralKeyPair.privKey)
).then(function(sharedSecret) {
return Internal.HKDF(
sharedSecret, util.toArrayBuffer(ratchet.rootKey), "WhisperRatchet"
);
}).then(function(masterKey) {
session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = {
messageKeys : {},
chainKey : { counter : -1, key : masterKey[1] }
};
ratchet.rootKey = masterKey[0];
});
}
};
libsignal.SessionBuilder = function (storage, remoteAddress) {
@ -35162,7 +35160,7 @@ SessionCipher.prototype = {
}
var builder = new SessionBuilder(this.storage, this.remoteAddress);
return builder.processV3(record, preKeyProto).then(function(preKeyId) {
var session = record.getSessionOrIdentityKeyByBaseKey(preKeyProto.baseKey);
var session = record.getSessionByBaseKey(preKeyProto.baseKey);
return this.doDecryptWhisperMessage(
preKeyProto.message.toArrayBuffer(), session
).then(function(plaintext) {

View file

@ -33906,7 +33906,7 @@ Curve25519Worker.prototype = {
*/
var Internal = Internal || {};
Internal.crypto = function() {
(function() {
'use strict';
var crypto = window.crypto;
@ -33927,7 +33927,7 @@ Internal.crypto = function() {
}
};
return {
Internal.crypto = {
getRandomBytes: function(size) {
var array = new Uint8Array(size);
crypto.getRandomValues(array);
@ -34024,7 +34024,16 @@ Internal.crypto = function() {
return Internal.curve25519.verify(pubKey, msg, sig);
}
};
}();
// HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes
Internal.HKDF = function(input, salt, info) {
if (salt.byteLength != 32)
throw new Error("Got salt of incorrect length");
return Internal.crypto.HKDF(input, salt, util.toArrayBuffer(info));
}
})();
/* vim: ts=4:sw=4
*
@ -34156,17 +34165,6 @@ window.libsignal = window.libsignal || {};
libsignal.protocol = function() {
var self = {};
/*****************************
*** Internal Crypto stuff ***
*****************************/
Internal.HKDF = function(input, salt, info) {
// HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes
if (salt.byteLength != 32)
throw new Error("Got salt of incorrect length");
return Internal.crypto.HKDF(input, salt, util.toArrayBuffer(info));
}
var verifyMAC = function(data, key, mac, length) {
return Internal.crypto.sign(key, data).then(function(calculated_mac) {
if (mac.byteLength != length || calculated_mac.byteLength < length) {
@ -34187,27 +34185,6 @@ libsignal.protocol = function() {
/******************************
*** Ratchet implementation ***
******************************/
Internal.calculateRatchet = function(session, remoteKey, sending) {
var ratchet = session.currentRatchet;
return Internal.crypto.ECDHE(remoteKey, util.toArrayBuffer(ratchet.ephemeralKeyPair.privKey)).then(function(sharedSecret) {
return Internal.HKDF(sharedSecret, util.toArrayBuffer(ratchet.rootKey), "WhisperRatchet").then(function(masterKey) {
var ephemeralPublicKey;
if (sending) {
ephemeralPublicKey = ratchet.ephemeralKeyPair.pubKey;
}
else {
ephemeralPublicKey = remoteKey;
}
session[util.toString(ephemeralPublicKey)] = {
messageKeys: {},
chainKey: { counter: -1, key: masterKey[1] }
};
ratchet.rootKey = masterKey[0];
});
});
}
self.createIdentityKeyRecvSocket = function() {
var socketInfo = {};
var keyPair;
@ -34499,10 +34476,12 @@ Internal.SessionRecord = function() {
haveOpenSession: function() {
return this.registrationId !== null;
},
getSessionOrIdentityKeyByBaseKey: function(baseKey) {
var sessions = this._sessions;
var preferredSession = this._sessions[util.toString(baseKey)];
getSessionByBaseKey: function(baseKey) {
return this._sessions[util.toString(baseKey)];
},
getSessionOrIdentityKeyByBaseKey: function(baseKey) {
var preferredSession = this.getSessionByBaseKey(baseKey);
if (preferredSession !== undefined) {
return preferredSession;
}
@ -34753,15 +34732,31 @@ SessionBuilder.prototype = {
}.bind(this));
},
processV3: function(record, message) {
var preKeyPair, signedPreKeyPair;
var session = record.getSessionOrIdentityKeyByBaseKey(message.baseKey);
return Promise.all([
this.storage.loadPreKey(message.preKeyId),
this.storage.loadSignedPreKey(message.signedPreKeyId),
]).then(function(results) {
preKeyPair = results[0];
signedPreKeyPair = results[1];
}).then(function() {
var preKeyPair, signedPreKeyPair, session;
return this.storage.isTrustedIdentity(
this.remoteAddress.getName(), message.identityKey.toArrayBuffer()
).then(function(trusted) {
if (!trusted) {
var e = new Error('Unknown identity key');
e.identityKey = message.identityKey.toArrayBuffer();
throw e;
}
return Promise.all([
this.storage.loadPreKey(message.preKeyId),
this.storage.loadSignedPreKey(message.signedPreKeyId),
]).then(function(results) {
preKeyPair = results[0];
signedPreKeyPair = results[1];
});
}.bind(this)).then(function() {
session = record.getSessionByBaseKey(message.baseKey);
if (session) {
console.log("Duplicate PreKeyMessage for session");
return;
}
session = record.getOpenSession();
if (signedPreKeyPair === undefined) {
// Session may or may not be the right one, but if its not, we
// can't do anything about it ...fall through and let
@ -34772,24 +34767,9 @@ SessionBuilder.prototype = {
throw new Error("Missing Signed PreKey for PreKeyWhisperMessage");
}
}
if (session !== undefined) {
// Duplicate PreKeyMessage for session:
if (util.isEqual(session.indexInfo.baseKey, message.baseKey)) {
return;
}
// We already had a session/known identity key:
if (util.isEqual(session.indexInfo.remoteIdentityKey, message.identityKey)) {
// If the identity key matches the previous one, close the
// previous one and use the new one
record.archiveCurrentState();
} else {
// ...otherwise create an error that the UI will pick up
// and ask the user if they want to re-negotiate
var e = new Error('Unknown identity key');
e.identityKey = message.identityKey.toArrayBuffer();
throw e;
}
if (session !== undefined) {
record.archiveCurrentState();
}
if (message.preKeyId && !preKeyPair) {
console.log('Invalid prekey id');
@ -34878,18 +34858,36 @@ SessionBuilder.prototype = {
session.indexInfo.baseKey = ourEphemeralKey.pubKey;
return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) {
session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey;
return Internal.calculateRatchet(session, theirSignedPubKey, true).then(function() {
return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() {
return session;
});
});
}.bind(this));
} else {
session.indexInfo.baseKey = theirEphemeralPubKey;
session.currentRatchet.ephemeralKeyPair = ourSignedKey;
return session;
}
});
});
}.bind(this));
}.bind(this));
},
calculateSendingRatchet: function(session, remoteKey) {
var ratchet = session.currentRatchet;
return Internal.crypto.ECDHE(
remoteKey, util.toArrayBuffer(ratchet.ephemeralKeyPair.privKey)
).then(function(sharedSecret) {
return Internal.HKDF(
sharedSecret, util.toArrayBuffer(ratchet.rootKey), "WhisperRatchet"
);
}).then(function(masterKey) {
session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = {
messageKeys : {},
chainKey : { counter : -1, key : masterKey[1] }
};
ratchet.rootKey = masterKey[0];
});
}
};
libsignal.SessionBuilder = function (storage, remoteAddress) {
@ -35048,7 +35046,7 @@ SessionCipher.prototype = {
}
var builder = new SessionBuilder(this.storage, this.remoteAddress);
return builder.processV3(record, preKeyProto).then(function(preKeyId) {
var session = record.getSessionOrIdentityKeyByBaseKey(preKeyProto.baseKey);
var session = record.getSessionByBaseKey(preKeyProto.baseKey);
return this.doDecryptWhisperMessage(
preKeyProto.message.toArrayBuffer(), session
).then(function(plaintext) {