summaryrefslogtreecommitdiff
path: root/frontend/beta
authorGiulio Cesare Solaroli <giulio.cesare@clipperz.com>2014-06-02 11:39:16 (UTC)
committer Giulio Cesare Solaroli <giulio.cesare@clipperz.com>2014-06-02 16:35:38 (UTC)
commit0422224521f62da210d1ae6ee15ecdf09f47f1f8 (patch) (side-by-side diff)
treedf7c0394fbcd1f8bc588ca8aab3ee83f5dc9f0cf /frontend/beta
parent7fdb41fa2b1f621636882ad9059c1f3ecfb74083 (diff)
downloadclipperz-0422224521f62da210d1ae6ee15ecdf09f47f1f8.zip
clipperz-0422224521f62da210d1ae6ee15ecdf09f47f1f8.tar.gz
clipperz-0422224521f62da210d1ae6ee15ecdf09f47f1f8.tar.bz2
Fixed authentication procedure for offline copy
Diffstat (limited to 'frontend/beta') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js47
1 files changed, 37 insertions, 10 deletions
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
index 1a5caff..b0b9b63 100644
--- a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
@@ -1,464 +1,491 @@
/*
Copyright 2008-2013 Clipperz Srl
This file is part of Clipperz, the online password manager.
For further information about its features and functionalities please
refer to http://www.clipperz.com.
* Clipperz is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* Clipperz 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 Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
*/
try { if (typeof(Clipperz.PM.Proxy.Offline) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.PM.Proxy.Offline.DataStore depends on Clipperz.PM.Proxy.Offline!";
}
//=============================================================================
Clipperz.PM.Proxy.Offline.DataStore = function(args) {
args = args || {};
this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
this._shouldPayTolls = args.shouldPayTolls || false;
this._tolls = {};
this._connections = {};
+ this._C = null;
this._b = null;
this._B = null;
this._A = null;
this._userData = null;
return this;
}
//Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
Clipperz.PM.Proxy.Offline.DataStore.prototype = MochiKit.Base.update(null, {
//-------------------------------------------------------------------------
'isReadOnly': function () {
return this._isReadOnly;
},
//-------------------------------------------------------------------------
'shouldPayTolls': function() {
return this._shouldPayTolls;
},
//-------------------------------------------------------------------------
'data': function () {
return this._data;
},
//-------------------------------------------------------------------------
'tolls': function () {
return this._tolls;
},
//-------------------------------------------------------------------------
'connections': function () {
return this._connections;
},
//=========================================================================
'resetData': function() {
this._data = {
'users': {
'catchAllUser': {
__masterkey_test_value__: 'masterkey',
s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00',
v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
}
}
};
},
//-------------------------------------------------------------------------
'setupWithEncryptedData': function(someData) {
this._data = Clipperz.Base.deepClone(someData);
},
//-------------------------------------------------------------------------
'setupWithData': function(someData) {
var deferredResult;
var resultData;
var i, c;
//Clipperz.log(">>> Proxy.Test.setupWithData");
resultData = this._data;
deferredResult = new MochiKit.Async.Deferred();
c = someData['users'].length;
for (i=0; i<c; i++) {
var newConnection;
var recordConfiguration;
deferredResult.addCallback(MochiKit.Base.method(this, 'userSerializedEncryptedData', someData['users'][i]));
deferredResult.addCallback(MochiKit.Base.bind(function(aUserSerializationContext) {
//console.log("SERIALIZED USER", aUserSerializationContext);
resultData['users'][aUserSerializationContext['credentials']['C']] = {
's': aUserSerializationContext['credentials']['s'],
'v': aUserSerializationContext['credentials']['v'],
'version': aUserSerializationContext['data']['connectionVersion'],
'userDetails': aUserSerializationContext['encryptedData']['user']['header'],
'userDetailsVersion': aUserSerializationContext['encryptedData']['user']['version'],
'statistics': aUserSerializationContext['encryptedData']['user']['statistics'],
'lock': aUserSerializationContext['encryptedData']['user']['lock'],
'records': this.rearrangeRecordsData(aUserSerializationContext['encryptedData']['records'])
}
}, this));
}
deferredResult.addCallback(MochiKit.Base.bind(function() {
//console.log("this._data", resultData);
this._data = resultData;
}, this));
deferredResult.callback();
//Clipperz.log("<<< Proxy.Test.setupWithData");
return deferredResult;
},
//=========================================================================
+ 'C': function() {
+ return this._C;
+ },
+
+ 'set_C': function(aValue) {
+ this._C = aValue;
+ },
+
+ //-------------------------------------------------------------------------
+
'b': function() {
return this._b;
},
'set_b': function(aValue) {
this._b = aValue;
},
//-------------------------------------------------------------------------
'B': function() {
return this._B;
},
'set_B': function(aValue) {
this._B = aValue;
},
//-------------------------------------------------------------------------
'A': function() {
return this._A;
},
'set_A': function(aValue) {
this._A = aValue;
},
//-------------------------------------------------------------------------
'userData': function() {
return this._userData;
},
'setUserData': function(aValue) {
this._userData = aValue;
},
//=========================================================================
'getTollForRequestType': function (aRequestType) {
var result;
var targetValue;
var cost;
targetValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
switch (aRequestType) {
case 'REGISTER':
cost = 5;
break;
case 'CONNECT':
cost = 5;
break;
case 'MESSAGE':
cost = 2;
break;
}
result = {
requestType: aRequestType,
targetValue: targetValue,
cost: cost
}
if (this.shouldPayTolls()) {
this.tolls()[targetValue] = result;
}
return result;
},
//-------------------------------------------------------------------------
'checkToll': function (aFunctionName, someParameters) {
if (this.shouldPayTolls()) {
var localToll;
var tollParameters;
tollParameters = someParameters['toll'];
localToll = this.tolls()[tollParameters['targetValue']];
if (localToll != null) {
if (! Clipperz.PM.Toll.validate(tollParameters['targetValue'], tollParameters['toll'], localToll['cost'])) {
throw "Toll value too low.";
};
} else {
throw "Missing toll";
}
}
},
//=========================================================================
-
- 'processMessage': function(aFunctionName, someParameters) {
+
+ 'processMessage': function (aFunctionName, someParameters) {
var result;
switch(aFunctionName) {
case 'knock':
result = this._knock(someParameters);
break;
case 'registration':
this.checkToll(aFunctionName, someParameters);
result = this._registration(someParameters.parameters);
break;
case 'handshake':
this.checkToll(aFunctionName, someParameters);
result = this._handshake(someParameters.parameters);
break;
case 'message':
this.checkToll(aFunctionName, someParameters);
result = this._message(someParameters.parameters);
break;
case 'logout':
result = this._logout(someParameters.parameters);
break;
}
return result;
},
//=========================================================================
'_knock': function(someParameters) {
var result;
result = {
toll: this.getTollForRequestType(someParameters['requestType'])
// toll: {
// requestType: someParameters['requestType'],
// targetValue: "3a1ba0be23580f902885c6c8a6b035e228ed1ca74d77de5f9bb0e0c899f07cfe",
// cost:
// }
}
return result;
},
//-------------------------------------------------------------------------
'_registration': function(someParameters) {
//console.log("_registration", someParameters);
if (this.isReadOnly() == false) {
if (typeof(this.data()['users'][someParameters['credentials']['C']]) == 'undefined') {
this.data()['users'][someParameters['credentials']['C']] = {
's': someParameters['credentials']['s'],
'v': someParameters['credentials']['v'],
'version': someParameters['credentials']['version'],
// 'lock': someParameters['user']['lock'],
'lock': Clipperz.Crypto.Base.generateRandomSeed(),
// 'maxNumberOfRecords': '100',
'userDetails': someParameters['user']['header'],
'statistics': someParameters['user']['statistics'],
'userDetailsVersion': someParameters['user']['version'],
'records': {}
}
} else {
throw "user already exists";
}
} else {
- throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
+ throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
}
result = {
result: {
'lock': this.data()['users'][someParameters['credentials']['C']]['lock'],
'result': 'done'
- },
+ },
toll: this.getTollForRequestType('CONNECT')
}
return MochiKit.Async.succeed(result);
},
//-------------------------------------------------------------------------
'_handshake': function(someParameters) {
var result;
var nextTollRequestType;
//Clipperz.log(">>> Proxy.Offline.DataStore._handshake");
result = {};
if (someParameters.message == "connect") {
var userData;
var randomBytes;
var b, B, v;
//console.log(">>> Proxy.Offline.DataStore._handshake.connect", someParameters);
userData = this.data()['users'][someParameters.parameters.C];
if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
this.setUserData(userData);
} else {
this.setUserData(this.data()['users']['catchAllUser']);
}
randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
+ this.set_C(someParameters.parameters.C);
this.set_b(new Clipperz.Crypto.BigInt(randomBytes, 16));
v = new Clipperz.Crypto.BigInt(this.userData()['v'], 16);
- this.set_B(v.add(Clipperz.Crypto.SRP.g().powerModule(this.b(), Clipperz.Crypto.SRP.n())));
+ this.set_B((Clipperz.Crypto.SRP.k().multiply(v)).add(Clipperz.Crypto.SRP.g().powerModule(this.b(), Clipperz.Crypto.SRP.n())));
this.set_A(someParameters.parameters.A);
result['s'] = this.userData()['s'];
result['B'] = this.B().asString(16);
nextTollRequestType = 'CONNECT';
} else if (someParameters.message == "credentialCheck") {
- var v, u, S, A, K, M1;
+ var v, u, s, S, A, K, M1;
+ var stringHash = function (aValue) {
+ return Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aValue)).toHexString().substring(2);
+ };
//console.log(">>> Proxy.Offline.DataStore._handshake.credentialCheck", someParameters);
v = new Clipperz.Crypto.BigInt(this.userData()['v'], 16);
- u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(this.B().asString(10))).toHexString(), 16);
A = new Clipperz.Crypto.BigInt(this.A(), 16);
+ u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + this.B().asString(10))).toHexString(), 16);
+ s = new Clipperz.Crypto.BigInt(this.userData()['s'], 16);
S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(this.b(), Clipperz.Crypto.SRP.n());
- K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2);
+ K = stringHash(S.asString(10));
- M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + this.B().asString(10) + K)).toHexString().slice(2);
+ M1 = stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ stringHash(this.C()) +
+ s.asString(10) +
+ A.asString(10) +
+ this.B().asString(10) +
+ K
+ );
if (someParameters.parameters.M1 == M1) {
var M2;
- M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2);
+ M2 = stringHash(
+ A.asString(10) +
+ someParameters.parameters.M1 +
+ K
+ );
result['M2'] = M2;
} else {
throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error");
}
nextTollRequestType = 'MESSAGE';
} else if (someParameters.message == "oneTimePassword") {
var otpData;
//console.log("HANDSHAKE WITH OTP", someParameters.parameters.oneTimePasswordKey);
//console.log("someParameters", someParameters);
//console.log("data.OTP", Clipperz.Base.serializeJSON(this.data()['onetimePasswords']));
otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey];
try {
if (typeof(otpData) != 'undefined') {
if (otpData['status'] == 'ACTIVE') {
if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) {
result = {
'data': otpData['data'],
'version': otpData['version']
}
otpData['status'] = 'REQUESTED';
} else {
otpData['status'] = 'DISABLED';
throw "The requested One Time Password has been disabled, due to a wrong keyChecksum";
}
} else {
throw "The requested One Time Password was not active";
}
} else {
throw "The requested One Time Password has not been found"
}
} catch (exception) {
result = {
'data': Clipperz.PM.Crypto.randomKey(),
'version': Clipperz.PM.Connection.communicationProtocol.currentVersion
}
}
nextTollRequestType = 'CONNECT';
} else {
MochiKit.Logging.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
}
//console.log("<<< Proxy.Offline._handshake", result);
result = {
result: result,
toll: this.getTollForRequestType(nextTollRequestType)
}
return MochiKit.Async.succeed(result);
},
//-------------------------------------------------------------------------
'_message': function(someParameters) {
var result;
result = {};
//=====================================================================
//
// R E A D - O N L Y M e t h o d s
//
//=====================================================================
if (someParameters.message == 'getUserDetails') {
var recordsStats;
var recordReference;
//try {
recordsStats = {};
for (recordReference in this.userData()['records']) {
recordsStats[recordReference] = {
'updateDate': this.userData()['records'][recordReference]['updateDate']
}
}
result['header'] = this.userDetails();
result['statistics'] = this.statistics();
result['maxNumberOfRecords'] = this.userData()['maxNumberOfRecords'];
result['version'] = this.userData()['userDetailsVersion'];
result['recordsStats'] = recordsStats;
if (this.isReadOnly() == false) {
var lock;
if (typeof(this.userData()['lock']) == 'undefined') {
this.userData()['lock'] = "<<LOCK>>";
}
result['lock'] = this.userData()['lock'];
}
//} catch (exception) {
// console.log("*#*#*#*#*#*#*", exception);
// throw exception;