summaryrefslogtreecommitdiff
path: root/frontend
Side-by-side diff
Diffstat (limited to 'frontend') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/Clipperz/Base.js28
-rw-r--r--frontend/beta/js/Clipperz/Crypto/PRNG.js130
-rw-r--r--frontend/beta/js/Clipperz/Crypto/SRP.js67
-rw-r--r--frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js2
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js4
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js22
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js2
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js47
-rw-r--r--frontend/delta/js/Clipperz/Crypto/PRNG.js128
-rw-r--r--frontend/delta/js/Clipperz/Crypto/SRP.js53
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js27
-rw-r--r--frontend/gamma/js/Clipperz/Crypto/PRNG.js128
-rw-r--r--frontend/gamma/js/Clipperz/Crypto/SRP.js53
-rw-r--r--frontend/gamma/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js35
14 files changed, 390 insertions, 336 deletions
diff --git a/frontend/beta/js/Clipperz/Base.js b/frontend/beta/js/Clipperz/Base.js
index cf40314..1c6faa1 100644
--- a/frontend/beta/js/Clipperz/Base.js
+++ b/frontend/beta/js/Clipperz/Base.js
@@ -201,96 +201,124 @@ MochiKit.Base.update(Clipperz.Base, {
return result;
},
//-------------------------------------------------------------------------
'evalJSON': function(aString) {
/*
var result;
// check for XSS injection
if (/<script>/.test(aString)) {
throw "error";
}
if (/<iframe>/.test(aString)) {
throw "error";
}
result = MochiKit.Base.evalJSON(aString);
return result;
*/
// return MochiKit.Base.evalJSON(aString);
return JSON2.parse(aString);
},
'serializeJSON': function(anObject) {
// return MochiKit.Base.serializeJSON(anObject);
return JSON2.stringify(anObject);
},
//-------------------------------------------------------------------------
'sanitizeString': function(aValue) {
var result;
if (Clipperz.Base.objectType(aValue) == 'string') {
result = aValue;
result = result.replace(/</img,"&lt;");
result = result.replace(/>/img,"&gt;");
} else {
result = aValue;
}
return result;
},
+ 'javascriptInjectionPattern': new RegExp("javascript:\/\/\"", "g"),
+
+ 'sanitizeUrl': function(aValue) {
+ var result;
+
+ if ((aValue != null) && this.javascriptInjectionPattern.test(aValue)) {
+ result = aValue.replace(this.javascriptInjectionPattern, '');
+ console.log("sanitized url", aValue, result);
+ } else {
+ result = aValue;
+ }
+
+ return result;
+ },
+
+ 'sanitizeFavicon': function(aValue) {
+ var result;
+
+ if ((aValue != null) && this.javascriptInjectionPattern.test(aValue)) {
+ result = aValue.replace(this.javascriptInjectionPattern, '');
+ console.log("sanitized favicon", aValue, result);
+ } else {
+ result = aValue;
+ }
+
+ return result;
+ },
+
//-------------------------------------------------------------------------
'exception': {
'AbstractMethod': new MochiKit.Base.NamedError("Clipperz.Base.exception.AbstractMethod"),
'UnknownType': new MochiKit.Base.NamedError("Clipperz.Base.exception.UnknownType"),
'VulnerabilityIssue': new MochiKit.Base.NamedError("Clipperz.Base.exception.VulnerabilityIssue")
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
MochiKit.Base.registerComparator('Object dummy comparator',
function(a, b) {
return ((a.constructor == Object) && (b.constructor == Object));
},
function(a, b) {
var result;
var aKeys;
var bKeys;
//MochiKit.Logging.logDebug(">>> comparator");
//MochiKit.Logging.logDebug("- a: " + Clipperz.Base.serializeJSON(a));
//MochiKit.Logging.logDebug("- b: " + Clipperz.Base.serializeJSON(a));
aKeys = MochiKit.Base.keys(a).sort();
bKeys = MochiKit.Base.keys(b).sort();
result = MochiKit.Base.compare(aKeys, bKeys);
//if (result != 0) {
// MochiKit.Logging.logDebug("- comparator 'keys':");
// MochiKit.Logging.logDebug("- comparator aKeys: " + Clipperz.Base.serializeJSON(aKeys));
// MochiKit.Logging.logDebug("- comparator bKeys: " + Clipperz.Base.serializeJSON(bKeys));
//}
if (result == 0) {
var i, c;
c = aKeys.length;
for (i=0; (i<c) && (result == 0); i++) {
result = MochiKit.Base.compare(a[aKeys[i]], b[bKeys[i]]);
//if (result != 0) {
// MochiKit.Logging.logDebug("- comparator 'values':");
// MochiKit.Logging.logDebug("- comparator a[aKeys[i]]: " + Clipperz.Base.serializeJSON(a[aKeys[i]]));
// MochiKit.Logging.logDebug("- comparator b[bKeys[i]]: " + Clipperz.Base.serializeJSON(b[bKeys[i]]));
//}
}
diff --git a/frontend/beta/js/Clipperz/Crypto/PRNG.js b/frontend/beta/js/Clipperz/Crypto/PRNG.js
index b5c3f8a..6fdeca4 100644
--- a/frontend/beta/js/Clipperz/Crypto/PRNG.js
+++ b/frontend/beta/js/Clipperz/Crypto/PRNG.js
@@ -152,278 +152,230 @@ Clipperz.Crypto.PRNG.RandomnessSource.prototype = MochiKit.Base.update(null, {
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.TimeRandomnessSource = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
this._intervalTime = args.intervalTime || 1000;
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this.collectEntropy();
return this;
}
Clipperz.Crypto.PRNG.TimeRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
'intervalTime': function() {
return this._intervalTime;
},
//-------------------------------------------------------------------------
'collectEntropy': function() {
var now;
var entropyByte;
var intervalTime;
now = new Date();
entropyByte = (now.getTime() & 0xff);
intervalTime = this.intervalTime();
if (this.boostMode() == true) {
intervalTime = intervalTime / 9;
}
this.updateGeneratorWithValue(entropyByte);
setTimeout(this.collectEntropy, intervalTime);
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 5;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
Clipperz.Crypto.PRNG.MouseRandomnessSource = function(args) {
args = args || {};
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this._numberOfBitsToCollectAtEachEvent = 4;
this._randomBitsCollector = 0;
this._numberOfRandomBitsCollected = 0;
MochiKit.Signal.connect(document, 'onmousemove', this, 'collectEntropy');
return this;
}
Clipperz.Crypto.PRNG.MouseRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
//-------------------------------------------------------------------------
'numberOfBitsToCollectAtEachEvent': function() {
return this._numberOfBitsToCollectAtEachEvent;
},
//-------------------------------------------------------------------------
'randomBitsCollector': function() {
return this._randomBitsCollector;
},
'setRandomBitsCollector': function(aValue) {
this._randomBitsCollector = aValue;
},
'appendRandomBitsToRandomBitsCollector': function(aValue) {
var collectedBits;
var numberOfRandomBitsCollected;
numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
+ collectedBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
+ this.setRandomBitsCollector(collectedBits);
numberOfRandomBitsCollected += this.numberOfBitsToCollectAtEachEvent();
if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
+ this.updateGeneratorWithValue(collectedBits);
numberOfRandomBitsCollected = 0;
this.setRandomBitsCollector(0);
}
this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
},
//-------------------------------------------------------------------------
'numberOfRandomBitsCollected': function() {
return this._numberOfRandomBitsCollected;
},
'setNumberOfRandomBitsCollected': function(aValue) {
this._numberOfRandomBitsCollected = aValue;
},
//-------------------------------------------------------------------------
'collectEntropy': function(anEvent) {
var mouseLocation;
var randomBit;
var mask;
mask = 0xffffffff >>> (32 - this.numberOfBitsToCollectAtEachEvent());
mouseLocation = anEvent.mouse().client;
randomBit = ((mouseLocation.x ^ mouseLocation.y) & mask);
this.appendRandomBitsToRandomBitsCollector(randomBit)
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 1;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource = function(args) {
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource = function(args) {
args = args || {};
- Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
- this._randomBitsCollector = 0;
- this._numberOfRandomBitsCollected = 0;
+ this._intervalTime = args.intervalTime || 1000;
+ this._browserCrypto = args.browserCrypto;
- MochiKit.Signal.connect(document, 'onkeypress', this, 'collectEntropy');
+ Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
+ this.collectEntropy();
return this;
}
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
-
- //-------------------------------------------------------------------------
-
- 'randomBitsCollector': function() {
- return this._randomBitsCollector;
- },
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
- 'setRandomBitsCollector': function(aValue) {
- this._randomBitsCollector = aValue;
+ 'intervalTime': function() {
+ return this._intervalTime;
},
-
- 'appendRandomBitToRandomBitsCollector': function(aValue) {
- var collectedBits;
- var numberOfRandomBitsCollected;
-
- numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
- numberOfRandomBitsCollected ++;
-
- if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
- numberOfRandomBitsCollected = 0;
- this.setRandomBitsCollector(0);
- }
-
- this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
+
+ 'browserCrypto': function () {
+ return this._browserCrypto;
},
//-------------------------------------------------------------------------
- 'numberOfRandomBitsCollected': function() {
- return this._numberOfRandomBitsCollected;
- },
-
- 'setNumberOfRandomBitsCollected': function(aValue) {
- this._numberOfRandomBitsCollected = aValue;
- },
+ 'collectEntropy': function() {
+ var bytesToCollect;
- //-------------------------------------------------------------------------
+ if (this.boostMode() == true) {
+ bytesToCollect = 64;
+ } else {
+ bytesToCollect = 8;
+ }
- 'collectEntropy': function(anEvent) {
-/*
- var mouseLocation;
- var randomBit;
-
- mouseLocation = anEvent.mouse().client;
-
- randomBit = ((mouseLocation.x ^ mouseLocation.y) & 0x1);
- this.appendRandomBitToRandomBitsCollector(randomBit);
-*/
- },
-
- //-------------------------------------------------------------------------
+ var randomValuesArray = new Uint8Array(bytesToCollect);
+ this.browserCrypto().getRandomValues(randomValuesArray);
+ for (var i = 0; i < randomValuesArray.length; i++) {
+ this.updateGeneratorWithValue(randomValuesArray[i]);
+ }
- 'numberOfRandomBits': function() {
- return 1;
+ setTimeout(this.collectEntropy, this.intervalTime());
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Fortuna = function(args) {
var i,c;
args = args || {};
this._key = args.seed || null;
if (this._key == null) {
this._counter = 0;
this._key = new Clipperz.ByteArray();
} else {
this._counter = 1;
}
this._aesKey = null;
this._firstPoolReseedLevel = args.firstPoolReseedLevel || 32 || 64;
this._numberOfEntropyAccumulators = args.numberOfEntropyAccumulators || 32;
this._accumulators = [];
c = this.numberOfEntropyAccumulators();
for (i=0; i<c; i++) {
this._accumulators.push(new Clipperz.Crypto.PRNG.EntropyAccumulator());
}
this._randomnessSources = [];
this._reseedCounter = 0;
return this;
}
Clipperz.Crypto.PRNG.Fortuna.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Fortuna";
},
//-------------------------------------------------------------------------
'key': function() {
return this._key;
},
'setKey': function(aValue) {
@@ -562,133 +514,127 @@ MochiKit.Logging.logWarning("Fortuna generator has not enough entropy, yet!");
}
return result;
},
//-------------------------------------------------------------------------
'addRandomByte': function(aSourceId, aPoolId, aRandomValue) {
var selectedAccumulator;
selectedAccumulator = this.accumulators()[aPoolId];
selectedAccumulator.addRandomByte(aRandomValue);
if (aPoolId == 0) {
MochiKit.Signal.signal(this, 'addedRandomByte')
if (selectedAccumulator.stack().length() > this.firstPoolReseedLevel()) {
this.reseed();
}
}
},
//-------------------------------------------------------------------------
'numberOfEntropyAccumulators': function() {
return this._numberOfEntropyAccumulators;
},
//-------------------------------------------------------------------------
'randomnessSources': function() {
return this._randomnessSources;
},
'addRandomnessSource': function(aRandomnessSource) {
aRandomnessSource.setGenerator(this);
aRandomnessSource.setSourceId(this.randomnessSources().length);
this.randomnessSources().push(aRandomnessSource);
if (this.isReadyToGenerateRandomValues() == false) {
aRandomnessSource.setBoostMode(true);
}
},
//-------------------------------------------------------------------------
'deferredEntropyCollection': function(aValue) {
var result;
-//MochiKit.Logging.logDebug(">>> PRNG.deferredEntropyCollection");
if (this.isReadyToGenerateRandomValues()) {
-//MochiKit.Logging.logDebug("--- PRNG.deferredEntropyCollection - 1");
result = aValue;
} else {
-//MochiKit.Logging.logDebug("--- PRNG.deferredEntropyCollection - 2");
var deferredResult;
Clipperz.NotificationCenter.notify(this, 'updatedProgressState', 'collectingEntropy', true);
deferredResult = new MochiKit.Async.Deferred();
-// deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.1 - PRNG.deferredEntropyCollection - 1: " + res); return res;});
deferredResult.addCallback(MochiKit.Base.partial(MochiKit.Async.succeed, aValue));
-// deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.2 - PRNG.deferredEntropyCollection - 2: " + res); return res;});
MochiKit.Signal.connect(this,
'readyToGenerateRandomBytes',
deferredResult,
'callback');
result = deferredResult;
}
-//MochiKit.Logging.logDebug("<<< PRNG.deferredEntropyCollection - result: " + result);
return result;
},
//-------------------------------------------------------------------------
'fastEntropyAccumulationForTestingPurpose': function() {
while (! this.isReadyToGenerateRandomValues()) {
this.addRandomByte(Math.floor(Math.random() * 32), Math.floor(Math.random() * 32), Math.floor(Math.random() * 256));
}
},
//-------------------------------------------------------------------------
-
+/*
'dump': function(appendToDoc) {
var tbl;
var i,c;
tbl = document.createElement("table");
tbl.border = 0;
with (tbl.style) {
border = "1px solid lightgrey";
fontFamily = 'Helvetica, Arial, sans-serif';
fontSize = '8pt';
//borderCollapse = "collapse";
}
var hdr = tbl.createTHead();
var hdrtr = hdr.insertRow(0);
// document.createElement("tr");
{
var ntd;
ntd = hdrtr.insertCell(0);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("#"));
ntd = hdrtr.insertCell(1);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("s"));
ntd = hdrtr.insertCell(2);
ntd.colSpan = this.firstPoolReseedLevel();
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("base values"));
ntd = hdrtr.insertCell(3);
ntd.colSpan = 20;
ntd.style.borderBottom = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("extra values"));
}
c = this.accumulators().length;
for (i=0; i<c ; i++) {
var currentAccumulator;
var bdytr;
var bdytd;
var ii, cc;
@@ -704,146 +650,156 @@ MochiKit.Logging.logWarning("Fortuna generator has not enough entropy, yet!");
bdytd = bdytr.insertCell(1);
bdytd.style.borderRight = "1px solid lightgrey";
bdytd.style.color = "gray";
bdytd.appendChild(document.createTextNode("" + currentAccumulator.stack().length()));
cc = Math.max(currentAccumulator.stack().length(), this.firstPoolReseedLevel());
for (ii=0; ii<cc; ii++) {
var cellText;
bdytd = bdytr.insertCell(ii + 2);
if (ii < currentAccumulator.stack().length()) {
cellText = Clipperz.ByteArray.byteToHex(currentAccumulator.stack().byteAtIndex(ii));
} else {
cellText = "_";
}
if (ii == (this.firstPoolReseedLevel() - 1)) {
bdytd.style.borderRight = "1px solid lightgrey";
}
bdytd.appendChild(document.createTextNode(cellText));
}
}
if (appendToDoc) {
var ne = document.createElement("div");
ne.id = "entropyGeneratorStatus";
with (ne.style) {
fontFamily = "Courier New, monospace";
fontSize = "12px";
lineHeight = "16px";
borderTop = "1px solid black";
padding = "10px";
}
if (document.getElementById(ne.id)) {
MochiKit.DOM.swapDOM(ne.id, ne);
} else {
document.body.appendChild(ne);
}
ne.appendChild(tbl);
}
return tbl;
},
-
+*/
//-----------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Random = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
return this;
}
Clipperz.Crypto.PRNG.Random.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Random";
},
//-------------------------------------------------------------------------
'getRandomBytes': function(aSize) {
//Clipperz.Profile.start("Clipperz.Crypto.PRNG.Random.getRandomBytes");
var result;
var i,c;
result = new Clipperz.ByteArray()
c = aSize || 1;
for (i=0; i<c; i++) {
result.appendByte((Math.random()*255) & 0xff);
}
//Clipperz.Profile.stop("Clipperz.Crypto.PRNG.Random.getRandomBytes");
return result;
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
_clipperz_crypt_prng_defaultPRNG = null;
Clipperz.Crypto.PRNG.defaultRandomGenerator = function() {
if (_clipperz_crypt_prng_defaultPRNG == null) {
_clipperz_crypt_prng_defaultPRNG = new Clipperz.Crypto.PRNG.Fortuna();
//.............................................................
//
// TimeRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.TimeRandomnessSource({intervalTime:111});
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
// MouseRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.MouseRandomnessSource();
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
- // KeyboardRandomnessSource
+ // CryptoRandomRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
+ var browserCrypto;
- newRandomnessSource = new Clipperz.Crypto.PRNG.KeyboardRandomnessSource();
- _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ if (window.crypto && window.crypto.getRandomValues) {
+ browserCrypto = window.crypto;
+ } else if (window.msCrypto && window.msCrypto.getRandomValues) {
+ browserCrypto = window.msCrypto;
+ } else {
+ browserCrypto = null;
+ }
+
+ if (browserCrypto != null) {
+ newRandomnessSource = new Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource({'browserCrypto':browserCrypto});
+ _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ }
}
-
}
return _clipperz_crypt_prng_defaultPRNG;
};
//#############################################################################
Clipperz.Crypto.PRNG.exception = {
NotEnoughEntropy: new MochiKit.Base.NamedError("Clipperz.Crypto.PRNG.exception.NotEnoughEntropy")
};
MochiKit.DOM.addLoadEvent(Clipperz.Crypto.PRNG.defaultRandomGenerator);
diff --git a/frontend/beta/js/Clipperz/Crypto/SRP.js b/frontend/beta/js/Clipperz/Crypto/SRP.js
index 8cc80ba..8c522ad 100644
--- a/frontend/beta/js/Clipperz/Crypto/SRP.js
+++ b/frontend/beta/js/Clipperz/Crypto/SRP.js
@@ -1,301 +1,320 @@
/*
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.ByteArray) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
}
try { if (typeof(Clipperz.Crypto.BigInt) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.BigInt!";
}
try { if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.PRNG!";
}
if (typeof(Clipperz.Crypto.SRP) == 'undefined') { Clipperz.Crypto.SRP = {}; }
Clipperz.Crypto.SRP.VERSION = "0.1";
Clipperz.Crypto.SRP.NAME = "Clipperz.Crypto.SRP";
//#############################################################################
MochiKit.Base.update(Clipperz.Crypto.SRP, {
'_n': null,
'_g': null,
+ '_k': null,
+
//-------------------------------------------------------------------------
'n': function() {
if (Clipperz.Crypto.SRP._n == null) {
Clipperz.Crypto.SRP._n = new Clipperz.Crypto.BigInt("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
}
return Clipperz.Crypto.SRP._n;
},
//-------------------------------------------------------------------------
'g': function() {
if (Clipperz.Crypto.SRP._g == null) {
Clipperz.Crypto.SRP._g = new Clipperz.Crypto.BigInt(2); // eventually 5 (as suggested on the Diffi-Helmann documentation)
}
return Clipperz.Crypto.SRP._g;
},
+ 'k': function() {
+ if (Clipperz.Crypto.SRP._k == null) {
+// Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt(this.stringHash(this.n().asString() + this.g().asString()), 16);
+ Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt("64398bff522814e306a97cb9bfc4364b7eed16a8c17c5208a40a2bad2933c8e", 16);
+ }
+
+ return Clipperz.Crypto.SRP._k;
+ },
+
//-----------------------------------------------------------------------------
'exception': {
'InvalidValue': new MochiKit.Base.NamedError("Clipperz.Crypto.SRP.exception.InvalidValue")
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
//
// S R P C o n n e c t i o n version 1.0
//
//=============================================================================
Clipperz.Crypto.SRP.Connection = function (args) {
args = args || {};
this._C = args.C;
this._P = args.P;
this.hash = args.hash;
this._a = null;
this._A = null;
this._s = null;
this._B = null;
this._x = null;
this._u = null;
this._K = null;
this._M1 = null;
this._M2 = null;
this._sessionKey = null;
return this;
}
Clipperz.Crypto.SRP.Connection.prototype = MochiKit.Base.update(null, {
'toString': function () {
return "Clipperz.Crypto.SRP.Connection (username: " + this.username() + "). Status: " + this.statusDescription();
},
//-------------------------------------------------------------------------
'C': function () {
return this._C;
},
//-------------------------------------------------------------------------
'P': function () {
return this._P;
},
//-------------------------------------------------------------------------
'a': function () {
if (this._a == null) {
this._a = new Clipperz.Crypto.BigInt(Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2), 16);
// this._a = new Clipperz.Crypto.BigInt("37532428169486597638072888476611365392249575518156687476805936694442691012367", 10);
-//MochiKit.Logging.logDebug("SRP a: " + this._a);
}
return this._a;
},
//-------------------------------------------------------------------------
'A': function () {
if (this._A == null) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
+ // Warning: this value should be strictly greater than zero
this._A = Clipperz.Crypto.SRP.g().powerModule(this.a(), Clipperz.Crypto.SRP.n());
-
- if (this._A.equals(0)) {
-MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'A' to 0.");
+ if (this._A.equals(0) || negative(this._A)) {
+ MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'A' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
-//MochiKit.Logging.logDebug("SRP A: " + this._A);
}
return this._A;
},
//-------------------------------------------------------------------------
's': function () {
return this._s;
-//MochiKit.Logging.logDebug("SRP s: " + this._S);
},
'set_s': function(aValue) {
this._s = aValue;
},
//-------------------------------------------------------------------------
'B': function () {
return this._B;
},
'set_B': function(aValue) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
- if (! aValue.equals(0)) {
- this._B = aValue;
-//MochiKit.Logging.logDebug("SRP B: " + this._B);
- } else {
-MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'B' to 0.");
+ // Warning: this value should be strictly greater than zero
+ this._B = aValue;
+ if (this._B.equals(0) || negative(this._B)) {
+ MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'B' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
},
//-------------------------------------------------------------------------
'x': function () {
if (this._x == null) {
this._x = new Clipperz.Crypto.BigInt(this.stringHash(this.s().asString(16, 64) + this.P()), 16);
-//MochiKit.Logging.logDebug("SRP x: " + this._x);
}
return this._x;
},
//-------------------------------------------------------------------------
'u': function () {
if (this._u == null) {
- this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.B().asString()), 16);
-//MochiKit.Logging.logDebug("SRP u: " + this._u);
+ this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.A().asString() + this.B().asString()), 16);
}
return this._u;
},
//-------------------------------------------------------------------------
'S': function () {
if (this._S == null) {
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
this._S = bigint.powerModule(
- bigint.subtract(this.B(), bigint.powerModule(srp.g(), this.x(), srp.n())),
- bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
- srp.n()
+ bigint.subtract(
+ this.B(),
+ bigint.multiply(
+ Clipperz.Crypto.SRP.k(),
+ bigint.powerModule(srp.g(), this.x(), srp.n())
+ )
+ ),
+ bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
+ srp.n()
)
-//MochiKit.Logging.logDebug("SRP S: " + this._S);
}
return this._S;
},
//-------------------------------------------------------------------------
'K': function () {
if (this._K == null) {
this._K = this.stringHash(this.S().asString());
-//MochiKit.Logging.logDebug("SRP K: " + this._K);
}
return this._K;
},
//-------------------------------------------------------------------------
'M1': function () {
if (this._M1 == null) {
- this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
-//MochiKit.Logging.logDebug("SRP M1: " + this._M1);
+// this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
+
+ // http://srp.stanford.edu/design.html
+ // User -> Host: M = H(H(N) xor H(g), H(I), s, A, B, K)
+
+ this._M1 = this.stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ this.stringHash(this.C()) +
+ this.s().asString() +
+ this.A().asString() +
+ this.B().asString() +
+ this.K()
+ );
+//console.log("M1", this._M1);
}
return this._M1;
},
//-------------------------------------------------------------------------
'M2': function () {
if (this._M2 == null) {
this._M2 = this.stringHash(this.A().asString(10) + this.M1() + this.K());
-//MochiKit.Logging.logDebug("SRP M2: " + this._M2);
+//console.log("M2", this._M2);
}
return this._M2;
},
//=========================================================================
'serverSideCredentialsWithSalt': function(aSalt) {
var result;
var s, x, v;
s = aSalt;
x = this.stringHash(s + this.P());
v = Clipperz.Crypto.SRP.g().powerModule(new Clipperz.Crypto.BigInt(x, 16), Clipperz.Crypto.SRP.n());
result = {};
result['C'] = this.C();
result['s'] = s;
result['v'] = v.asString(16);
return result;
},
'serverSideCredentials': function() {
var result;
var s;
s = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
result = this.serverSideCredentialsWithSalt(s);
return result;
},
//=========================================================================
/*
'computeServerSide_S': function(b) {
var result;
var v;
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
v = new Clipperz.Crypto.BigInt(srpConnection.serverSideCredentialsWithSalt(this.s().asString(16, 64)).v, 16);
// _S = (this.A().multiply(this.v().modPow(this.u(), this.n()))).modPow(this.b(), this.n());
result = bigint.powerModule(
diff --git a/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js b/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js
index 2295d3f..369b9ce 100644
--- a/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js
+++ b/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js
@@ -93,97 +93,97 @@ Clipperz.PM.BookmarkletProcessor.prototype = MochiKit.Base.update(null, {
},
//-------------------------------------------------------------------------
'configuration': function() {
return this._configuration;
},
//-------------------------------------------------------------------------
'recordTitle': function() {
if (this._recordTitle == null) {
this._recordTitle = this.configuration().page.title;
}
return this._recordTitle;
},
//-------------------------------------------------------------------------
'fields': function() {
return this.configuration().form.inputs;
},
//-------------------------------------------------------------------------
'editableFields': function() {
if (this._editableFields == null) {
this._editableFields = MochiKit.Base.filter(function(aField) {
var result;
var type;
type = aField['type'].toLowerCase();
result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
return result;
}, this.fields())
}
return this._editableFields;
},
//-------------------------------------------------------------------------
'hostname': function() {
if (this._hostname == null) {
var actionUrl;
- actionUrl = this.configuration()['form']['attributes']['action'];
+ actionUrl = Clipperz.Base.sanitizeUrl(this.configuration()['form']['attributes']['action']);
//MochiKit.Logging.logDebug("+++ actionUrl: " + actionUrl);
this._hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
}
return this._hostname;
},
'favicon': function() {
if (this._favicon == null) {
this._favicon = "http://" + this.hostname() + "/favicon.ico";
//MochiKit.Logging.logDebug("+++ favicon: " + this._favicon);
}
return this._favicon;
},
//-------------------------------------------------------------------------
'record': function() {
if (this._record == null) {
var record;
var recordVersion;
var directLogin;
var bindings;
var i,c;
record = new Clipperz.PM.DataModel.Record({
label:this.recordTitle(),
notes:"",
user:this.user()
});
recordVersion = new Clipperz.PM.DataModel.RecordVersion(record, {})
record.setCurrentVersion(recordVersion);
bindings = {};
c = this.editableFields().length;
for (i=0; i<c; i++) {
var formField;
var recordField;
//MochiKit.Logging.logDebug(">>> adding a field");
formField = this.editableFields()[i];
recordField = new Clipperz.PM.DataModel.RecordField({
recordVersion:recordVersion,
label:formField['name'],
value:formField['value'],
type:Clipperz.PM.Strings.inputTypeToRecordFieldType[formField['type']],
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js
index 0e4640e..a5a4697 100644
--- a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js
@@ -55,115 +55,115 @@ YAHOO.extendX(Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent, C
//-------------------------------------------------------------------------
'directLoginBinding': function() {
return this._directLoginBinding;
},
//-------------------------------------------------------------------------
'render': function() {
// Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', style:'font-weight:bold;', html:this.directLoginBinding().key()})
// Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', html:this.directLoginBinding().value()})
//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.render");
Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginBindingLabelTD', children:[
{tag:'span', html:this.directLoginBinding().key()}
]});
//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.render - 1");
Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginBindingValueTD', children:[
{tag:'div', id:this.getId('editModeBox'), children:[
{tag:'select', id:this.getId('select'), children:this.recordFieldOptions()}
]},
{tag:'div', id:this.getId('viewModeBox'), children:[
{tag:'span', id:this.getId('viewValue'), html:""}
]}
]});
//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.render - 2");
this.getElement('editModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
this.getElement('viewModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
this.update();
//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.render");
},
//-------------------------------------------------------------------------
'recordFieldOptions': function() {
var result;
var option;
var recordFieldKey;
var recordFields;
//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.recordFieldOptions");
recordFields = this.directLoginBinding().directLogin().record().currentVersion().fields();
result = [];
option = {tag:'option', value:null, html:'---'};
result.push(option);
for (recordFieldKey in recordFields) {
// TODO: remove the value: field and replace it with element.dom.value = <some value>
- option = {tag:'option', value:recordFieldKey, html:recordFields[recordFieldKey].label()}
+ option = {tag:'option', value:recordFieldKey, html:Clipperz.Base.sanitizeString(recordFields[recordFieldKey].label())}
if (recordFieldKey == this.directLoginBinding().fieldKey()) {
option['selected'] = true;
}
result.push(option);
}
//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.recordFieldOptions");
return result;
},
//-------------------------------------------------------------------------
'syncAndUpdateEditMode': function() {
this.synchronizeComponentValues();
this.updateEditMode();
},
'updateEditMode': function() {
var selectElementBox;
//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.updateEditMode");
this.getElement('viewModeBox').hide();
selectElementBox = this.getElement('editModeBox');
selectElementBox.update("");
Clipperz.YUI.DomHelper.append(selectElementBox.dom, {tag:'select', id:this.getId('select'), children:this.recordFieldOptions()});
/*
selectElement = this.getElement('select');
selectElement.update("");
MochiKit.Iter.forEach(this.recordFieldOptions(), function(anOption) {
Clipperz.YUI.DomHelper.append(selectElement.dom, anOption);
});
*/
this.getElement('editModeBox').show();
//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.updateEditMode");
},
//-------------------------------------------------------------------------
'updateViewMode': function() {
//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.updateViewMode");
this.getElement('editModeBox').hide();
this.getElement('viewModeBox').show();
- this.getElement('viewValue').update(this.directLoginBinding().field().label());
+ this.getElement('viewValue').update(Clipperz.Base.sanitizeString(this.directLoginBinding().field().label()));
//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.updateViewMode");
},
//-------------------------------------------------------------------------
'synchronizeComponentValues': function() {
//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.synchronizeComponentValues")
//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.synchronizeComponentValues - 1 - " + this.getId('select'));
this.directLoginBinding().setFieldKey(this.getDom('select').value);
//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.synchronizeComponentValues");
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js
index c0cfa3c..56d9d59 100644
--- a/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js
@@ -1,187 +1,195 @@
/*
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/.
*/
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
//#############################################################################
Clipperz.PM.DataModel.DirectLogin = function(args) {
//MochiKit.Logging.logDebug(">>> new Clipperz.PM.DataModel.DirectLogin");
//console.log(">>> new Clipperz.PM.DataModel.DirectLogin - args: %o", args);
//console.log("--- formData: %s", Clipperz.Base.serializeJSON(args.formData));
args = args || {};
//MochiKit.Logging.logDebug("--- new Clipperz.PM.DataModel.DirectLogin - args: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(args)));
this._record = args.record || null;
this._label = args.label || "unnamed record"
this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
- this._favicon = args.favicon || null;
+ this._favicon = Clipperz.Base.sanitizeFavicon(args.favicon) || null;
this._bookmarkletVersion = args.bookmarkletVersion || "0.1";
this._directLoginInputs = null;
this._formValues = args.formValues || {};
this.setFormData(args.formData || null);
//console.log("=== formData: %o", this.formData());
if (args.legacyBindingData == null) {
this.setBindingData(args.bindingData || null);
} else {
this.setLegacyBindingData(args.legacyBindingData);
}
this._fixedFavicon = null;
// this._formValues = args.formValues || (this.hasValuesToSet() ? {} : null);
//MochiKit.Logging.logDebug("<<< new Clipperz.PM.DataModel.DirectLogin");
return this;
}
Clipperz.PM.DataModel.DirectLogin.prototype = MochiKit.Base.update(null, {
'remove': function() {
this.record().removeDirectLogin(this);
},
//-------------------------------------------------------------------------
'record': function() {
return this._record;
},
//-------------------------------------------------------------------------
'user': function() {
return this.record().user();
},
//-------------------------------------------------------------------------
'reference': function() {
return this._reference;
},
//-------------------------------------------------------------------------
'label': function() {
return this._label;
},
'setLabel': function(aValue) {
this._label = aValue;
},
//-------------------------------------------------------------------------
'favicon': function() {
if (this._favicon == null) {
var actionUrl;
var hostname;
- actionUrl = this.formData()['attributes']['action'];
+ actionUrl = this.action();
hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
- this._favicon = "http://" + hostname + "/favicon.ico";
+ this._favicon = Clipperz.Base.sanitizeFavicon("http://" + hostname + "/favicon.ico");
}
return this._favicon;
},
//-------------------------------------------------------------------------
'fixedFavicon': function() {
var result;
if (this._fixedFavicon == null) {
result = this.favicon();
if (Clipperz_IEisBroken) {
if (this.user().preferences().disableUnsecureFaviconLoadingForIE()) {
if (result.indexOf('https://') != 0) {
result = Clipperz.PM.Strings['defaultFaviconUrl_IE'];
this.setFixedFavicon(result);
}
}
}
} else {
result = this._fixedFavicon;
}
return result;
},
'setFixedFavicon': function(aValue) {
this._fixedFavicon = aValue;
},
+ 'action': function () {
+ var result;
+
+ result = Clipperz.Base.sanitizeUrl(this.formData()['attributes']['action']);
+
+ return result;
+ },
+
//-------------------------------------------------------------------------
'bookmarkletVersion': function() {
return this._bookmarkletVersion;
},
'setBookmarkletVersion': function(aValue) {
this._bookmarkletVersion = aValue;
},
//-------------------------------------------------------------------------
'formData': function() {
return this._formData;
},
'setFormData': function(aValue) {
var formData;
//MochiKit.Logging.logDebug(">>> DirectLogin.setFormData - " + Clipperz.Base.serializeJSON(aValue));
switch (this.bookmarkletVersion()) {
case "0.2":
formData = aValue;
break;
case "0.1":
//MochiKit.Logging.logDebug("--- DirectLogin.setFormData - fixing form data from bookmarklet version 0.1");
formData = this.fixFormDataFromBookmarkletVersion_0_1(aValue);
break;
}
this._formData = aValue;
this.setBookmarkletVersion("0.2");
//MochiKit.Logging.logDebug("--- DirectLogin.setFormData - formData: " + Clipperz.Base.serializeJSON(formData));
if (formData != null) {
var i,c;
this._directLoginInputs = [];
c = formData['inputs'].length;
for (i=0; i<c; i++) {
var directLoginInput;
directLoginInput = new Clipperz.PM.DataModel.DirectLoginInput(this, formData['inputs'][i]);
this._directLoginInputs.push(directLoginInput);
}
}
//MochiKit.Logging.logDebug("<<< DirectLogin.setFormData");
},
@@ -397,135 +405,135 @@ Clipperz.PM.DataModel.DirectLogin.prototype = MochiKit.Base.update(null, {
},
//=========================================================================
'runHttpAuthDirectLogin': function(aWindow) {
MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
var completeUrl;
var url;
url = this.bindings()['url'].field().value();
if (/^https?\:\/\//.test(url) == false) {
url = 'http://' + url;
}
if (Clipperz_IEisBroken === true) {
completeUrl = url;
} else {
var username;
var password;
username = this.bindings()['username'].field().value();
password = this.bindings()['password'].field().value();
/(^https?\:\/\/)?(.*)/.test(url);
completeUrl = RegExp.$1 + username + ':' + password + '@' + RegExp.$2;
}
MochiKit.DOM.currentWindow().location.href = completeUrl;
}, this));
},
//-------------------------------------------------------------------------
'runSubmitFormDirectLogin': function(aWindow) {
MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
var formElement;
var formSubmitFunction;
var submitButtons;
//MochiKit.Logging.logDebug("### runDirectLogin - 3");
// MochiKit.DOM.currentDocument().write('<html><head><title>' + this.label() + '</title><META http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body></body></html>')
//MochiKit.Logging.logDebug("### runDirectLogin - 3.1");
MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, MochiKit.DOM.H3(null, "Loading " + this.label() + " ..."));
//MochiKit.Logging.logDebug("### runDirectLogin - 4");
//console.log(this.formData()['attributes']);
formElement = MochiKit.DOM.FORM(MochiKit.Base.update({id:'directLoginForm'}, { 'method':this.formData()['attributes']['method'],
- 'action':this.formData()['attributes']['action']}));
+ 'action': this.action()}));
//MochiKit.Logging.logDebug("### runDirectLogin - 5");
formSubmitFunction = MochiKit.Base.method(formElement, 'submit');
//MochiKit.Logging.logDebug("### runDirectLogin - 6");
MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body,
MochiKit.DOM.DIV({style:'display:none; visibility:hidden;'}, formElement)
);
//MochiKit.Logging.logDebug("### runDirectLogin - 7");
MochiKit.DOM.appendChildNodes(formElement, MochiKit.Base.map( MochiKit.Base.methodcaller("formConfiguration"),
this.directLoginInputs()));
//MochiKit.Logging.logDebug("### runDirectLogin - 8");
submitButtons = MochiKit.Base.filter(function(anInputElement) {
//MochiKit.Logging.logDebug("### runDirectLogin - 8.1 - " + anInputElement);
//MochiKit.Logging.logDebug("### runDirectLogin - 8.2 - " + anInputElement.tagName);
//MochiKit.Logging.logDebug("### runDirectLogin - 8.3 - " + anInputElement.getAttribute('type'));
return ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('type').toLowerCase() == 'submit'));
}, formElement.elements)
//MochiKit.Logging.logDebug("### runDirectLogin - 9");
if (submitButtons.length == 0) {
//MochiKit.Logging.logDebug("### OLD submit")
if (Clipperz_IEisBroken == true) {
//MochiKit.Logging.logDebug("### runDirectLogin - 10");
formElement.submit();
} else {
//MochiKit.Logging.logDebug("### runDirectLogin - 11");
formSubmitFunction();
}
} else {
//MochiKit.Logging.logDebug("### NEW submit")
submitButtons[0].click();
}
}, this));
},
//-------------------------------------------------------------------------
'runDirectLogin': function(aNewWindow) {
var newWindow;
//console.log("formData.attributes", this.formData()['attributes']);
// if (/^javascript/.test(this.formData()['attributes']['action'])) {
- if ((/^(https?|webdav|ftp)\:/.test(this.formData()['attributes']['action']) == false) &&
- (this.formData()['attributes']['type'] != 'http_auth'))
- {
+ if ((/^(https?|webdav|ftp)\:/.test(this.action()) == false) &&
+ (this.formData()['attributes']['type'] != 'http_auth')
+ ) {
var messageBoxConfiguration;
if (typeof(aNewWindow) != 'undefined') {
aNewWindow.close();
}
messageBoxConfiguration = {};
messageBoxConfiguration.title = Clipperz.PM.Strings['VulnerabilityWarning_Panel_title'];
messageBoxConfiguration.msg = Clipperz.PM.Strings['VulnerabilityWarning_Panel_message'];
messageBoxConfiguration.animEl = YAHOO.ext.Element.get("mainDiv");
messageBoxConfiguration.progress = false;
messageBoxConfiguration.closable = false;
messageBoxConfiguration.buttons = {'cancel': Clipperz.PM.Strings['VulnerabilityWarning_Panel_buttonLabel']};
Clipperz.YUI.MessageBox.show(messageBoxConfiguration);
throw Clipperz.Base.exception.VulnerabilityIssue;
}
//MochiKit.Logging.logDebug("### runDirectLogin - 1 : " + Clipperz.Base.serializeJSON(this.serializedData()));
if (typeof(aNewWindow) == 'undefined') {
newWindow = window.open(Clipperz.PM.Strings['directLoginJumpPageUrl'], "");
} else {
newWindow = aNewWindow;
}
//MochiKit.Logging.logDebug("### runDirectLogin - 2");
if (this.formData()['attributes']['type'] == 'http_auth') {
this.runHttpAuthDirectLogin(newWindow);
} else {
this.runSubmitFormDirectLogin(newWindow)
}
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js
index 236d7c9..ba302da 100644
--- a/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js
@@ -2,97 +2,97 @@
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/.
*/
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
//#############################################################################
Clipperz.PM.DataModel.DirectLoginReference = function(args) {
args = args || {};
//MochiKit.Logging.logDebug(">>> new DirectLoginReference: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(args)));
//MochiKit.Logging.logDebug(">>> new DirectLoginReference - record: " + args.record);
this._user = args.user;
if (args.directLogin != null) {
this._reference = args.directLogin.reference();
this._recordReference = args.directLogin.record().reference();
this._label = args.directLogin.label();
this._favicon = args.directLogin.favicon() || null;
this._directLogin = args.directLogin;
this._record = args.directLogin.record();
} else {
this._reference = args.reference;
this._recordReference = args.record;
this._label = args.label;
- this._favicon = args.favicon || null;
+ this._favicon = Clipperz.Base.sanitizeFavicon(args.favicon) || null;
this._directLogin = null;
this._record = null;
}
this._fixedFavicon = null;
return this;
}
Clipperz.PM.DataModel.DirectLoginReference.prototype = MochiKit.Base.update(null, {
'user': function() {
return this._user;
},
//-------------------------------------------------------------------------
'reference': function() {
return this._reference;
},
//-------------------------------------------------------------------------
'synchronizeValues': function(aDirectLogin) {
this._label = aDirectLogin.label();
this._favicon = aDirectLogin.favicon();
},
//-------------------------------------------------------------------------
'label': function() {
return this._label;
},
//-------------------------------------------------------------------------
'recordReference': function() {
return this._recordReference;
},
//-------------------------------------------------------------------------
'record': function() {
//MochiKit.Logging.logDebug(">>> DirectLoginReference.record");
if (this._record == null) {
this._record = this.user().records()[this.recordReference()];
}
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,87 +1,88 @@
/*
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',
@@ -99,318 +100,344 @@ Clipperz.PM.Proxy.Offline.DataStore.prototype = MochiKit.Base.update(null, {
},
//-------------------------------------------------------------------------
'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,
diff --git a/frontend/delta/js/Clipperz/Crypto/PRNG.js b/frontend/delta/js/Clipperz/Crypto/PRNG.js
index c539f06..80d972f 100644
--- a/frontend/delta/js/Clipperz/Crypto/PRNG.js
+++ b/frontend/delta/js/Clipperz/Crypto/PRNG.js
@@ -1,71 +1,73 @@
/*
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/.
*/
+"use strict";
+
try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
}
try { if (typeof(Clipperz.Crypto.SHA) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.SHA!";
}
try { if (typeof(Clipperz.Crypto.AES) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.AES!";
}
if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { Clipperz.Crypto.PRNG = {}; }
//#############################################################################
Clipperz.Crypto.PRNG.EntropyAccumulator = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
this._stack = new Clipperz.ByteArray();
this._maxStackLengthBeforeHashing = args.maxStackLengthBeforeHashing || 256;
return this;
}
Clipperz.Crypto.PRNG.EntropyAccumulator.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.EntropyAccumulator";
},
//-------------------------------------------------------------------------
'stack': function() {
return this._stack;
},
'setStack': function(aValue) {
this._stack = aValue;
},
'resetStack': function() {
this.stack().reset();
},
'maxStackLengthBeforeHashing': function() {
return this._maxStackLengthBeforeHashing;
},
@@ -152,278 +154,230 @@ Clipperz.Crypto.PRNG.RandomnessSource.prototype = MochiKit.Base.update(null, {
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.TimeRandomnessSource = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
this._intervalTime = args.intervalTime || 1000;
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this.collectEntropy();
return this;
}
Clipperz.Crypto.PRNG.TimeRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
'intervalTime': function() {
return this._intervalTime;
},
//-------------------------------------------------------------------------
'collectEntropy': function() {
var now;
var entropyByte;
var intervalTime;
now = new Date();
entropyByte = (now.getTime() & 0xff);
intervalTime = this.intervalTime();
if (this.boostMode() == true) {
intervalTime = intervalTime / 9;
}
this.updateGeneratorWithValue(entropyByte);
setTimeout(this.collectEntropy, intervalTime);
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 5;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
Clipperz.Crypto.PRNG.MouseRandomnessSource = function(args) {
args = args || {};
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this._numberOfBitsToCollectAtEachEvent = 4;
this._randomBitsCollector = 0;
this._numberOfRandomBitsCollected = 0;
MochiKit.Signal.connect(document, 'onmousemove', this, 'collectEntropy');
return this;
}
Clipperz.Crypto.PRNG.MouseRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
//-------------------------------------------------------------------------
'numberOfBitsToCollectAtEachEvent': function() {
return this._numberOfBitsToCollectAtEachEvent;
},
//-------------------------------------------------------------------------
'randomBitsCollector': function() {
return this._randomBitsCollector;
},
'setRandomBitsCollector': function(aValue) {
this._randomBitsCollector = aValue;
},
'appendRandomBitsToRandomBitsCollector': function(aValue) {
var collectedBits;
var numberOfRandomBitsCollected;
numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
+ collectedBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
+ this.setRandomBitsCollector(collectedBits);
numberOfRandomBitsCollected += this.numberOfBitsToCollectAtEachEvent();
if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
+ this.updateGeneratorWithValue(collectedBits);
numberOfRandomBitsCollected = 0;
this.setRandomBitsCollector(0);
}
this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
},
//-------------------------------------------------------------------------
'numberOfRandomBitsCollected': function() {
return this._numberOfRandomBitsCollected;
},
'setNumberOfRandomBitsCollected': function(aValue) {
this._numberOfRandomBitsCollected = aValue;
},
//-------------------------------------------------------------------------
'collectEntropy': function(anEvent) {
var mouseLocation;
var randomBit;
var mask;
mask = 0xffffffff >>> (32 - this.numberOfBitsToCollectAtEachEvent());
mouseLocation = anEvent.mouse().client;
randomBit = ((mouseLocation.x ^ mouseLocation.y) & mask);
this.appendRandomBitsToRandomBitsCollector(randomBit)
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 1;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource = function(args) {
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource = function(args) {
args = args || {};
- Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
- this._randomBitsCollector = 0;
- this._numberOfRandomBitsCollected = 0;
+ this._intervalTime = args.intervalTime || 1000;
+ this._browserCrypto = args.browserCrypto;
- MochiKit.Signal.connect(document, 'onkeypress', this, 'collectEntropy');
+ Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
+ this.collectEntropy();
return this;
}
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
- //-------------------------------------------------------------------------
-
- 'randomBitsCollector': function() {
- return this._randomBitsCollector;
- },
-
- 'setRandomBitsCollector': function(aValue) {
- this._randomBitsCollector = aValue;
+ 'intervalTime': function() {
+ return this._intervalTime;
},
-
- 'appendRandomBitToRandomBitsCollector': function(aValue) {
- var collectedBits;
- var numberOfRandomBitsCollected;
-
- numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
- numberOfRandomBitsCollected ++;
-
- if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
- numberOfRandomBitsCollected = 0;
- this.setRandomBitsCollector(0);
- }
-
- this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
+
+ 'browserCrypto': function () {
+ return this._browserCrypto;
},
//-------------------------------------------------------------------------
- 'numberOfRandomBitsCollected': function() {
- return this._numberOfRandomBitsCollected;
- },
-
- 'setNumberOfRandomBitsCollected': function(aValue) {
- this._numberOfRandomBitsCollected = aValue;
- },
+ 'collectEntropy': function() {
+ var bytesToCollect;
- //-------------------------------------------------------------------------
+ if (this.boostMode() == true) {
+ bytesToCollect = 64;
+ } else {
+ bytesToCollect = 8;
+ }
- 'collectEntropy': function(anEvent) {
-/*
- var mouseLocation;
- var randomBit;
-
- mouseLocation = anEvent.mouse().client;
-
- randomBit = ((mouseLocation.x ^ mouseLocation.y) & 0x1);
- this.appendRandomBitToRandomBitsCollector(randomBit);
-*/
- },
-
- //-------------------------------------------------------------------------
+ var randomValuesArray = new Uint8Array(bytesToCollect);
+ this.browserCrypto().getRandomValues(randomValuesArray);
+ for (var i = 0; i < randomValuesArray.length; i++) {
+ this.updateGeneratorWithValue(randomValuesArray[i]);
+ }
- 'numberOfRandomBits': function() {
- return 1;
+ setTimeout(this.collectEntropy, this.intervalTime());
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Fortuna = function(args) {
var i,c;
args = args || {};
this._key = args.seed || null;
if (this._key == null) {
this._counter = 0;
this._key = new Clipperz.ByteArray();
} else {
this._counter = 1;
}
this._aesKey = null;
this._firstPoolReseedLevel = args.firstPoolReseedLevel || 32 || 64;
this._numberOfEntropyAccumulators = args.numberOfEntropyAccumulators || 32;
this._accumulators = [];
c = this.numberOfEntropyAccumulators();
for (i=0; i<c; i++) {
this._accumulators.push(new Clipperz.Crypto.PRNG.EntropyAccumulator());
}
this._randomnessSources = [];
this._reseedCounter = 0;
return this;
}
Clipperz.Crypto.PRNG.Fortuna.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Fortuna";
},
//-------------------------------------------------------------------------
'key': function() {
return this._key;
},
'setKey': function(aValue) {
@@ -590,97 +544,97 @@ Clipperz.logWarning("Fortuna generator has not enough entropy, yet!");
'randomnessSources': function() {
return this._randomnessSources;
},
'addRandomnessSource': function(aRandomnessSource) {
aRandomnessSource.setGenerator(this);
aRandomnessSource.setSourceId(this.randomnessSources().length);
this.randomnessSources().push(aRandomnessSource);
if (this.isReadyToGenerateRandomValues() == false) {
aRandomnessSource.setBoostMode(true);
}
},
//-------------------------------------------------------------------------
'deferredEntropyCollection': function(aValue) {
var result;
if (this.isReadyToGenerateRandomValues()) {
result = aValue;
} else {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("PRNG.deferredEntropyCollection");
deferredResult.addCallback(MochiKit.Base.partial(MochiKit.Async.succeed, aValue));
MochiKit.Signal.connect(this,
'readyToGenerateRandomBytes',
deferredResult,
'callback');
result = deferredResult;
}
return result;
},
//-------------------------------------------------------------------------
'fastEntropyAccumulationForTestingPurpose': function() {
while (! this.isReadyToGenerateRandomValues()) {
this.addRandomByte(Math.floor(Math.random() * 32), Math.floor(Math.random() * 32), Math.floor(Math.random() * 256));
}
},
//-------------------------------------------------------------------------
-
+/*
'dump': function(appendToDoc) {
var tbl;
var i,c;
tbl = document.createElement("table");
tbl.border = 0;
with (tbl.style) {
border = "1px solid lightgrey";
fontFamily = 'Helvetica, Arial, sans-serif';
fontSize = '8pt';
//borderCollapse = "collapse";
}
var hdr = tbl.createTHead();
var hdrtr = hdr.insertRow(0);
// document.createElement("tr");
{
var ntd;
ntd = hdrtr.insertCell(0);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("#"));
ntd = hdrtr.insertCell(1);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("s"));
ntd = hdrtr.insertCell(2);
ntd.colSpan = this.firstPoolReseedLevel();
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("base values"));
ntd = hdrtr.insertCell(3);
ntd.colSpan = 20;
ntd.style.borderBottom = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("extra values"));
}
c = this.accumulators().length;
for (i=0; i<c ; i++) {
var currentAccumulator;
var bdytr;
var bdytd;
var ii, cc;
@@ -696,146 +650,156 @@ Clipperz.logWarning("Fortuna generator has not enough entropy, yet!");
bdytd = bdytr.insertCell(1);
bdytd.style.borderRight = "1px solid lightgrey";
bdytd.style.color = "gray";
bdytd.appendChild(document.createTextNode("" + currentAccumulator.stack().length()));
cc = Math.max(currentAccumulator.stack().length(), this.firstPoolReseedLevel());
for (ii=0; ii<cc; ii++) {
var cellText;
bdytd = bdytr.insertCell(ii + 2);
if (ii < currentAccumulator.stack().length()) {
cellText = Clipperz.ByteArray.byteToHex(currentAccumulator.stack().byteAtIndex(ii));
} else {
cellText = "_";
}
if (ii == (this.firstPoolReseedLevel() - 1)) {
bdytd.style.borderRight = "1px solid lightgrey";
}
bdytd.appendChild(document.createTextNode(cellText));
}
}
if (appendToDoc) {
var ne = document.createElement("div");
ne.id = "entropyGeneratorStatus";
with (ne.style) {
fontFamily = "Courier New, monospace";
fontSize = "12px";
lineHeight = "16px";
borderTop = "1px solid black";
padding = "10px";
}
if (document.getElementById(ne.id)) {
MochiKit.DOM.swapDOM(ne.id, ne);
} else {
document.body.appendChild(ne);
}
ne.appendChild(tbl);
}
return tbl;
},
-
+*/
//-----------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Random = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
return this;
}
Clipperz.Crypto.PRNG.Random.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Random";
},
//-------------------------------------------------------------------------
'getRandomBytes': function(aSize) {
//Clipperz.Profile.start("Clipperz.Crypto.PRNG.Random.getRandomBytes");
var result;
var i,c;
result = new Clipperz.ByteArray()
c = aSize || 1;
for (i=0; i<c; i++) {
result.appendByte((Math.random()*255) & 0xff);
}
//Clipperz.Profile.stop("Clipperz.Crypto.PRNG.Random.getRandomBytes");
return result;
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
-_clipperz_crypt_prng_defaultPRNG = null;
+var _clipperz_crypt_prng_defaultPRNG = null;
Clipperz.Crypto.PRNG.defaultRandomGenerator = function() {
if (_clipperz_crypt_prng_defaultPRNG == null) {
_clipperz_crypt_prng_defaultPRNG = new Clipperz.Crypto.PRNG.Fortuna();
//.............................................................
//
// TimeRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.TimeRandomnessSource({intervalTime:111});
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
// MouseRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.MouseRandomnessSource();
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
- // KeyboardRandomnessSource
+ // CryptoRandomRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
+ var browserCrypto;
- newRandomnessSource = new Clipperz.Crypto.PRNG.KeyboardRandomnessSource();
- _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ if (window.crypto && window.crypto.getRandomValues) {
+ browserCrypto = window.crypto;
+ } else if (window.msCrypto && window.msCrypto.getRandomValues) {
+ browserCrypto = window.msCrypto;
+ } else {
+ browserCrypto = null;
+ }
+
+ if (browserCrypto != null) {
+ newRandomnessSource = new Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource({'browserCrypto':browserCrypto});
+ _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ }
}
-
}
return _clipperz_crypt_prng_defaultPRNG;
};
//#############################################################################
Clipperz.Crypto.PRNG.exception = {
NotEnoughEntropy: new MochiKit.Base.NamedError("Clipperz.Crypto.PRNG.exception.NotEnoughEntropy")
};
MochiKit.DOM.addLoadEvent(Clipperz.Crypto.PRNG.defaultRandomGenerator);
diff --git a/frontend/delta/js/Clipperz/Crypto/SRP.js b/frontend/delta/js/Clipperz/Crypto/SRP.js
index 597e72d..6898dfb 100644
--- a/frontend/delta/js/Clipperz/Crypto/SRP.js
+++ b/frontend/delta/js/Clipperz/Crypto/SRP.js
@@ -1,291 +1,320 @@
/*
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.ByteArray) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
}
try { if (typeof(Clipperz.Crypto.BigInt) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.BigInt!";
}
try { if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.PRNG!";
}
if (typeof(Clipperz.Crypto.SRP) == 'undefined') { Clipperz.Crypto.SRP = {}; }
Clipperz.Crypto.SRP.VERSION = "0.1";
Clipperz.Crypto.SRP.NAME = "Clipperz.Crypto.SRP";
//#############################################################################
MochiKit.Base.update(Clipperz.Crypto.SRP, {
'_n': null,
'_g': null,
+ '_k': null,
+
//-------------------------------------------------------------------------
'n': function() {
if (Clipperz.Crypto.SRP._n == null) {
Clipperz.Crypto.SRP._n = new Clipperz.Crypto.BigInt("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
}
return Clipperz.Crypto.SRP._n;
},
//-------------------------------------------------------------------------
'g': function() {
if (Clipperz.Crypto.SRP._g == null) {
Clipperz.Crypto.SRP._g = new Clipperz.Crypto.BigInt(2); // eventually 5 (as suggested on the Diffi-Helmann documentation)
}
return Clipperz.Crypto.SRP._g;
},
+ 'k': function() {
+ if (Clipperz.Crypto.SRP._k == null) {
+// Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt(this.stringHash(this.n().asString() + this.g().asString()), 16);
+ Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt("64398bff522814e306a97cb9bfc4364b7eed16a8c17c5208a40a2bad2933c8e", 16);
+ }
+
+ return Clipperz.Crypto.SRP._k;
+ },
+
//-----------------------------------------------------------------------------
'exception': {
'InvalidValue': new MochiKit.Base.NamedError("Clipperz.Crypto.SRP.exception.InvalidValue")
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
//
// S R P C o n n e c t i o n version 1.0
//
//=============================================================================
Clipperz.Crypto.SRP.Connection = function (args) {
args = args || {};
this._C = args.C;
this._P = args.P;
this.hash = args.hash;
this._a = null;
this._A = null;
this._s = null;
this._B = null;
this._x = null;
this._u = null;
this._K = null;
this._M1 = null;
this._M2 = null;
this._sessionKey = null;
return this;
}
Clipperz.Crypto.SRP.Connection.prototype = MochiKit.Base.update(null, {
'toString': function () {
return "Clipperz.Crypto.SRP.Connection (username: " + this.username() + "). Status: " + this.statusDescription();
},
//-------------------------------------------------------------------------
'C': function () {
return this._C;
},
//-------------------------------------------------------------------------
'P': function () {
return this._P;
},
//-------------------------------------------------------------------------
'a': function () {
if (this._a == null) {
this._a = new Clipperz.Crypto.BigInt(Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2), 16);
// this._a = new Clipperz.Crypto.BigInt("37532428169486597638072888476611365392249575518156687476805936694442691012367", 10);
}
return this._a;
},
//-------------------------------------------------------------------------
'A': function () {
if (this._A == null) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
+ // Warning: this value should be strictly greater than zero
this._A = Clipperz.Crypto.SRP.g().powerModule(this.a(), Clipperz.Crypto.SRP.n());
-
- if (this._A.equals(0)) {
+ if (this._A.equals(0) || negative(this._A)) {
Clipperz.logError("Clipperz.Crypto.SRP.Connection: trying to set 'A' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
}
return this._A;
},
//-------------------------------------------------------------------------
's': function () {
return this._s;
},
'set_s': function(aValue) {
this._s = aValue;
},
//-------------------------------------------------------------------------
'B': function () {
return this._B;
},
'set_B': function(aValue) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
- if (! aValue.equals(0)) {
- this._B = aValue;
- } else {
+ // Warning: this value should be strictly greater than zero
+ this._B = aValue;
+ if (this._B.equals(0) || negative(this._B)) {
Clipperz.logError("Clipperz.Crypto.SRP.Connection: trying to set 'B' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
},
//-------------------------------------------------------------------------
'x': function () {
if (this._x == null) {
this._x = new Clipperz.Crypto.BigInt(this.stringHash(this.s().asString(16, 64) + this.P()), 16);
}
return this._x;
},
//-------------------------------------------------------------------------
'u': function () {
if (this._u == null) {
- this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.B().asString()), 16);
+ this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.A().asString() + this.B().asString()), 16);
}
return this._u;
},
//-------------------------------------------------------------------------
'S': function () {
if (this._S == null) {
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
this._S = bigint.powerModule(
- bigint.subtract(this.B(), bigint.powerModule(srp.g(), this.x(), srp.n())),
- bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
- srp.n()
+ bigint.subtract(
+ this.B(),
+ bigint.multiply(
+ Clipperz.Crypto.SRP.k(),
+ bigint.powerModule(srp.g(), this.x(), srp.n())
+ )
+ ),
+ bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
+ srp.n()
)
}
return this._S;
},
//-------------------------------------------------------------------------
'K': function () {
if (this._K == null) {
this._K = this.stringHash(this.S().asString());
}
return this._K;
},
//-------------------------------------------------------------------------
'M1': function () {
if (this._M1 == null) {
- this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
+// this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
+
+ // http://srp.stanford.edu/design.html
+ // User -> Host: M = H(H(N) xor H(g), H(I), s, A, B, K)
+
+ this._M1 = this.stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ this.stringHash(this.C()) +
+ this.s().asString() +
+ this.A().asString() +
+ this.B().asString() +
+ this.K()
+ );
+//console.log("M1", this._M1);
}
return this._M1;
},
//-------------------------------------------------------------------------
'M2': function () {
if (this._M2 == null) {
this._M2 = this.stringHash(this.A().asString(10) + this.M1() + this.K());
+//console.log("M2", this._M2);
}
return this._M2;
},
//=========================================================================
'serverSideCredentialsWithSalt': function(aSalt) {
var result;
var s, x, v;
s = aSalt;
x = this.stringHash(s + this.P());
v = Clipperz.Crypto.SRP.g().powerModule(new Clipperz.Crypto.BigInt(x, 16), Clipperz.Crypto.SRP.n());
result = {};
result['C'] = this.C();
result['s'] = s;
result['v'] = v.asString(16);
return result;
},
'serverSideCredentials': function() {
var result;
var s;
s = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
result = this.serverSideCredentialsWithSalt(s);
return result;
},
//=========================================================================
/*
'computeServerSide_S': function(b) {
var result;
var v;
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
v = new Clipperz.Crypto.BigInt(srpConnection.serverSideCredentialsWithSalt(this.s().asString(16, 64)).v, 16);
// _S = (this.A().multiply(this.v().modPow(this.u(), this.n()))).modPow(this.b(), this.n());
result = bigint.powerModule(
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
index 3f16f70..d03f873 100644
--- a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
+++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
@@ -43,119 +43,134 @@ Clipperz.PM.Proxy.Offline.LocalStorageDataStore = function(args) {
return this;
}
Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.LocalStorageDataStore, Clipperz.PM.Proxy.Offline.DataStore, {
//=========================================================================
'_knock': function(aConnection, someParameters) {
var result;
result = {
toll: this.getTollForRequestType(someParameters['requestType'])
}
return result;
},
//-------------------------------------------------------------------------
'_registration': function(aConnection, someParameters) {
throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
},
//-------------------------------------------------------------------------
'_handshake': function(aConnection, someParameters) {
var result;
var nextTollRequestType;
result = {};
if (someParameters.message == "connect") {
var userData;
var randomBytes;
var v;
userData = this.data()['users'][someParameters.parameters.C];
if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
aConnection['userData'] = userData;
aConnection['C'] = someParameters.parameters.C;
} else {
aConnection['userData'] = this.data()['users']['catchAllUser'];
}
randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16);
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
- aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
+ aConnection['B'] = (Clipperz.Crypto.SRP.k().multiply(v)).add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
aConnection['A'] = someParameters.parameters.A;
result['s'] = aConnection['userData']['s'];
result['B'] = aConnection['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);
+ };
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
- u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16);
A = new Clipperz.Crypto.BigInt(aConnection['A'], 16);
+ u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10))).toHexString(), 16);
+ s = new Clipperz.Crypto.BigInt(aConnection['userData']['s'], 16);
S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['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) + aConnection['B'].asString(10) + K)).toHexString().slice(2);
+ M1 = stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ stringHash(aConnection['C']) +
+ s.asString(10) +
+ A.asString(10) +
+ aConnection['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;
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 {
Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
}
result = {
result: result,
toll: this.getTollForRequestType(nextTollRequestType)
}
return result;
diff --git a/frontend/gamma/js/Clipperz/Crypto/PRNG.js b/frontend/gamma/js/Clipperz/Crypto/PRNG.js
index c539f06..80d972f 100644
--- a/frontend/gamma/js/Clipperz/Crypto/PRNG.js
+++ b/frontend/gamma/js/Clipperz/Crypto/PRNG.js
@@ -1,71 +1,73 @@
/*
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/.
*/
+"use strict";
+
try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
}
try { if (typeof(Clipperz.Crypto.SHA) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.SHA!";
}
try { if (typeof(Clipperz.Crypto.AES) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.AES!";
}
if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { Clipperz.Crypto.PRNG = {}; }
//#############################################################################
Clipperz.Crypto.PRNG.EntropyAccumulator = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
this._stack = new Clipperz.ByteArray();
this._maxStackLengthBeforeHashing = args.maxStackLengthBeforeHashing || 256;
return this;
}
Clipperz.Crypto.PRNG.EntropyAccumulator.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.EntropyAccumulator";
},
//-------------------------------------------------------------------------
'stack': function() {
return this._stack;
},
'setStack': function(aValue) {
this._stack = aValue;
},
'resetStack': function() {
this.stack().reset();
},
'maxStackLengthBeforeHashing': function() {
return this._maxStackLengthBeforeHashing;
},
@@ -152,278 +154,230 @@ Clipperz.Crypto.PRNG.RandomnessSource.prototype = MochiKit.Base.update(null, {
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.TimeRandomnessSource = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
this._intervalTime = args.intervalTime || 1000;
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this.collectEntropy();
return this;
}
Clipperz.Crypto.PRNG.TimeRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
'intervalTime': function() {
return this._intervalTime;
},
//-------------------------------------------------------------------------
'collectEntropy': function() {
var now;
var entropyByte;
var intervalTime;
now = new Date();
entropyByte = (now.getTime() & 0xff);
intervalTime = this.intervalTime();
if (this.boostMode() == true) {
intervalTime = intervalTime / 9;
}
this.updateGeneratorWithValue(entropyByte);
setTimeout(this.collectEntropy, intervalTime);
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 5;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
Clipperz.Crypto.PRNG.MouseRandomnessSource = function(args) {
args = args || {};
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
this._numberOfBitsToCollectAtEachEvent = 4;
this._randomBitsCollector = 0;
this._numberOfRandomBitsCollected = 0;
MochiKit.Signal.connect(document, 'onmousemove', this, 'collectEntropy');
return this;
}
Clipperz.Crypto.PRNG.MouseRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
//-------------------------------------------------------------------------
'numberOfBitsToCollectAtEachEvent': function() {
return this._numberOfBitsToCollectAtEachEvent;
},
//-------------------------------------------------------------------------
'randomBitsCollector': function() {
return this._randomBitsCollector;
},
'setRandomBitsCollector': function(aValue) {
this._randomBitsCollector = aValue;
},
'appendRandomBitsToRandomBitsCollector': function(aValue) {
var collectedBits;
var numberOfRandomBitsCollected;
numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
+ collectedBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
+ this.setRandomBitsCollector(collectedBits);
numberOfRandomBitsCollected += this.numberOfBitsToCollectAtEachEvent();
if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
+ this.updateGeneratorWithValue(collectedBits);
numberOfRandomBitsCollected = 0;
this.setRandomBitsCollector(0);
}
this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
},
//-------------------------------------------------------------------------
'numberOfRandomBitsCollected': function() {
return this._numberOfRandomBitsCollected;
},
'setNumberOfRandomBitsCollected': function(aValue) {
this._numberOfRandomBitsCollected = aValue;
},
//-------------------------------------------------------------------------
'collectEntropy': function(anEvent) {
var mouseLocation;
var randomBit;
var mask;
mask = 0xffffffff >>> (32 - this.numberOfBitsToCollectAtEachEvent());
mouseLocation = anEvent.mouse().client;
randomBit = ((mouseLocation.x ^ mouseLocation.y) & mask);
this.appendRandomBitsToRandomBitsCollector(randomBit)
},
//-------------------------------------------------------------------------
'numberOfRandomBits': function() {
return 1;
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//*****************************************************************************
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource = function(args) {
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource = function(args) {
args = args || {};
- Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
- this._randomBitsCollector = 0;
- this._numberOfRandomBitsCollected = 0;
+ this._intervalTime = args.intervalTime || 1000;
+ this._browserCrypto = args.browserCrypto;
- MochiKit.Signal.connect(document, 'onkeypress', this, 'collectEntropy');
+ Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
+ this.collectEntropy();
return this;
}
-Clipperz.Crypto.PRNG.KeyboardRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
+Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
- //-------------------------------------------------------------------------
-
- 'randomBitsCollector': function() {
- return this._randomBitsCollector;
- },
-
- 'setRandomBitsCollector': function(aValue) {
- this._randomBitsCollector = aValue;
+ 'intervalTime': function() {
+ return this._intervalTime;
},
-
- 'appendRandomBitToRandomBitsCollector': function(aValue) {
- var collectedBits;
- var numberOfRandomBitsCollected;
-
- numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
- collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
- this.setRandomBitsCollector(collectetBits);
- numberOfRandomBitsCollected ++;
-
- if (numberOfRandomBitsCollected == 8) {
- this.updateGeneratorWithValue(collectetBits);
- numberOfRandomBitsCollected = 0;
- this.setRandomBitsCollector(0);
- }
-
- this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
+
+ 'browserCrypto': function () {
+ return this._browserCrypto;
},
//-------------------------------------------------------------------------
- 'numberOfRandomBitsCollected': function() {
- return this._numberOfRandomBitsCollected;
- },
-
- 'setNumberOfRandomBitsCollected': function(aValue) {
- this._numberOfRandomBitsCollected = aValue;
- },
+ 'collectEntropy': function() {
+ var bytesToCollect;
- //-------------------------------------------------------------------------
+ if (this.boostMode() == true) {
+ bytesToCollect = 64;
+ } else {
+ bytesToCollect = 8;
+ }
- 'collectEntropy': function(anEvent) {
-/*
- var mouseLocation;
- var randomBit;
-
- mouseLocation = anEvent.mouse().client;
-
- randomBit = ((mouseLocation.x ^ mouseLocation.y) & 0x1);
- this.appendRandomBitToRandomBitsCollector(randomBit);
-*/
- },
-
- //-------------------------------------------------------------------------
+ var randomValuesArray = new Uint8Array(bytesToCollect);
+ this.browserCrypto().getRandomValues(randomValuesArray);
+ for (var i = 0; i < randomValuesArray.length; i++) {
+ this.updateGeneratorWithValue(randomValuesArray[i]);
+ }
- 'numberOfRandomBits': function() {
- return 1;
+ setTimeout(this.collectEntropy, this.intervalTime());
},
//-------------------------------------------------------------------------
-
- 'pollingFrequency': function() {
- return 10;
- },
-
- //-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Fortuna = function(args) {
var i,c;
args = args || {};
this._key = args.seed || null;
if (this._key == null) {
this._counter = 0;
this._key = new Clipperz.ByteArray();
} else {
this._counter = 1;
}
this._aesKey = null;
this._firstPoolReseedLevel = args.firstPoolReseedLevel || 32 || 64;
this._numberOfEntropyAccumulators = args.numberOfEntropyAccumulators || 32;
this._accumulators = [];
c = this.numberOfEntropyAccumulators();
for (i=0; i<c; i++) {
this._accumulators.push(new Clipperz.Crypto.PRNG.EntropyAccumulator());
}
this._randomnessSources = [];
this._reseedCounter = 0;
return this;
}
Clipperz.Crypto.PRNG.Fortuna.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Fortuna";
},
//-------------------------------------------------------------------------
'key': function() {
return this._key;
},
'setKey': function(aValue) {
@@ -590,97 +544,97 @@ Clipperz.logWarning("Fortuna generator has not enough entropy, yet!");
'randomnessSources': function() {
return this._randomnessSources;
},
'addRandomnessSource': function(aRandomnessSource) {
aRandomnessSource.setGenerator(this);
aRandomnessSource.setSourceId(this.randomnessSources().length);
this.randomnessSources().push(aRandomnessSource);
if (this.isReadyToGenerateRandomValues() == false) {
aRandomnessSource.setBoostMode(true);
}
},
//-------------------------------------------------------------------------
'deferredEntropyCollection': function(aValue) {
var result;
if (this.isReadyToGenerateRandomValues()) {
result = aValue;
} else {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("PRNG.deferredEntropyCollection");
deferredResult.addCallback(MochiKit.Base.partial(MochiKit.Async.succeed, aValue));
MochiKit.Signal.connect(this,
'readyToGenerateRandomBytes',
deferredResult,
'callback');
result = deferredResult;
}
return result;
},
//-------------------------------------------------------------------------
'fastEntropyAccumulationForTestingPurpose': function() {
while (! this.isReadyToGenerateRandomValues()) {
this.addRandomByte(Math.floor(Math.random() * 32), Math.floor(Math.random() * 32), Math.floor(Math.random() * 256));
}
},
//-------------------------------------------------------------------------
-
+/*
'dump': function(appendToDoc) {
var tbl;
var i,c;
tbl = document.createElement("table");
tbl.border = 0;
with (tbl.style) {
border = "1px solid lightgrey";
fontFamily = 'Helvetica, Arial, sans-serif';
fontSize = '8pt';
//borderCollapse = "collapse";
}
var hdr = tbl.createTHead();
var hdrtr = hdr.insertRow(0);
// document.createElement("tr");
{
var ntd;
ntd = hdrtr.insertCell(0);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("#"));
ntd = hdrtr.insertCell(1);
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("s"));
ntd = hdrtr.insertCell(2);
ntd.colSpan = this.firstPoolReseedLevel();
ntd.style.borderBottom = "1px solid lightgrey";
ntd.style.borderRight = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("base values"));
ntd = hdrtr.insertCell(3);
ntd.colSpan = 20;
ntd.style.borderBottom = "1px solid lightgrey";
ntd.appendChild(document.createTextNode("extra values"));
}
c = this.accumulators().length;
for (i=0; i<c ; i++) {
var currentAccumulator;
var bdytr;
var bdytd;
var ii, cc;
@@ -696,146 +650,156 @@ Clipperz.logWarning("Fortuna generator has not enough entropy, yet!");
bdytd = bdytr.insertCell(1);
bdytd.style.borderRight = "1px solid lightgrey";
bdytd.style.color = "gray";
bdytd.appendChild(document.createTextNode("" + currentAccumulator.stack().length()));
cc = Math.max(currentAccumulator.stack().length(), this.firstPoolReseedLevel());
for (ii=0; ii<cc; ii++) {
var cellText;
bdytd = bdytr.insertCell(ii + 2);
if (ii < currentAccumulator.stack().length()) {
cellText = Clipperz.ByteArray.byteToHex(currentAccumulator.stack().byteAtIndex(ii));
} else {
cellText = "_";
}
if (ii == (this.firstPoolReseedLevel() - 1)) {
bdytd.style.borderRight = "1px solid lightgrey";
}
bdytd.appendChild(document.createTextNode(cellText));
}
}
if (appendToDoc) {
var ne = document.createElement("div");
ne.id = "entropyGeneratorStatus";
with (ne.style) {
fontFamily = "Courier New, monospace";
fontSize = "12px";
lineHeight = "16px";
borderTop = "1px solid black";
padding = "10px";
}
if (document.getElementById(ne.id)) {
MochiKit.DOM.swapDOM(ne.id, ne);
} else {
document.body.appendChild(ne);
}
ne.appendChild(tbl);
}
return tbl;
},
-
+*/
//-----------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
Clipperz.Crypto.PRNG.Random = function(args) {
args = args || {};
// MochiKit.Base.bindMethods(this);
return this;
}
Clipperz.Crypto.PRNG.Random.prototype = MochiKit.Base.update(null, {
'toString': function() {
return "Clipperz.Crypto.PRNG.Random";
},
//-------------------------------------------------------------------------
'getRandomBytes': function(aSize) {
//Clipperz.Profile.start("Clipperz.Crypto.PRNG.Random.getRandomBytes");
var result;
var i,c;
result = new Clipperz.ByteArray()
c = aSize || 1;
for (i=0; i<c; i++) {
result.appendByte((Math.random()*255) & 0xff);
}
//Clipperz.Profile.stop("Clipperz.Crypto.PRNG.Random.getRandomBytes");
return result;
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
-_clipperz_crypt_prng_defaultPRNG = null;
+var _clipperz_crypt_prng_defaultPRNG = null;
Clipperz.Crypto.PRNG.defaultRandomGenerator = function() {
if (_clipperz_crypt_prng_defaultPRNG == null) {
_clipperz_crypt_prng_defaultPRNG = new Clipperz.Crypto.PRNG.Fortuna();
//.............................................................
//
// TimeRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.TimeRandomnessSource({intervalTime:111});
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
// MouseRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
newRandomnessSource = new Clipperz.Crypto.PRNG.MouseRandomnessSource();
_clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
}
//.............................................................
//
- // KeyboardRandomnessSource
+ // CryptoRandomRandomnessSource
//
//.............................................................
{
var newRandomnessSource;
+ var browserCrypto;
- newRandomnessSource = new Clipperz.Crypto.PRNG.KeyboardRandomnessSource();
- _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ if (window.crypto && window.crypto.getRandomValues) {
+ browserCrypto = window.crypto;
+ } else if (window.msCrypto && window.msCrypto.getRandomValues) {
+ browserCrypto = window.msCrypto;
+ } else {
+ browserCrypto = null;
+ }
+
+ if (browserCrypto != null) {
+ newRandomnessSource = new Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource({'browserCrypto':browserCrypto});
+ _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
+ }
}
-
}
return _clipperz_crypt_prng_defaultPRNG;
};
//#############################################################################
Clipperz.Crypto.PRNG.exception = {
NotEnoughEntropy: new MochiKit.Base.NamedError("Clipperz.Crypto.PRNG.exception.NotEnoughEntropy")
};
MochiKit.DOM.addLoadEvent(Clipperz.Crypto.PRNG.defaultRandomGenerator);
diff --git a/frontend/gamma/js/Clipperz/Crypto/SRP.js b/frontend/gamma/js/Clipperz/Crypto/SRP.js
index 597e72d..6898dfb 100644
--- a/frontend/gamma/js/Clipperz/Crypto/SRP.js
+++ b/frontend/gamma/js/Clipperz/Crypto/SRP.js
@@ -1,291 +1,320 @@
/*
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.ByteArray) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
}
try { if (typeof(Clipperz.Crypto.BigInt) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.BigInt!";
}
try { if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.PRNG!";
}
if (typeof(Clipperz.Crypto.SRP) == 'undefined') { Clipperz.Crypto.SRP = {}; }
Clipperz.Crypto.SRP.VERSION = "0.1";
Clipperz.Crypto.SRP.NAME = "Clipperz.Crypto.SRP";
//#############################################################################
MochiKit.Base.update(Clipperz.Crypto.SRP, {
'_n': null,
'_g': null,
+ '_k': null,
+
//-------------------------------------------------------------------------
'n': function() {
if (Clipperz.Crypto.SRP._n == null) {
Clipperz.Crypto.SRP._n = new Clipperz.Crypto.BigInt("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
}
return Clipperz.Crypto.SRP._n;
},
//-------------------------------------------------------------------------
'g': function() {
if (Clipperz.Crypto.SRP._g == null) {
Clipperz.Crypto.SRP._g = new Clipperz.Crypto.BigInt(2); // eventually 5 (as suggested on the Diffi-Helmann documentation)
}
return Clipperz.Crypto.SRP._g;
},
+ 'k': function() {
+ if (Clipperz.Crypto.SRP._k == null) {
+// Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt(this.stringHash(this.n().asString() + this.g().asString()), 16);
+ Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt("64398bff522814e306a97cb9bfc4364b7eed16a8c17c5208a40a2bad2933c8e", 16);
+ }
+
+ return Clipperz.Crypto.SRP._k;
+ },
+
//-----------------------------------------------------------------------------
'exception': {
'InvalidValue': new MochiKit.Base.NamedError("Clipperz.Crypto.SRP.exception.InvalidValue")
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
//#############################################################################
//
// S R P C o n n e c t i o n version 1.0
//
//=============================================================================
Clipperz.Crypto.SRP.Connection = function (args) {
args = args || {};
this._C = args.C;
this._P = args.P;
this.hash = args.hash;
this._a = null;
this._A = null;
this._s = null;
this._B = null;
this._x = null;
this._u = null;
this._K = null;
this._M1 = null;
this._M2 = null;
this._sessionKey = null;
return this;
}
Clipperz.Crypto.SRP.Connection.prototype = MochiKit.Base.update(null, {
'toString': function () {
return "Clipperz.Crypto.SRP.Connection (username: " + this.username() + "). Status: " + this.statusDescription();
},
//-------------------------------------------------------------------------
'C': function () {
return this._C;
},
//-------------------------------------------------------------------------
'P': function () {
return this._P;
},
//-------------------------------------------------------------------------
'a': function () {
if (this._a == null) {
this._a = new Clipperz.Crypto.BigInt(Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2), 16);
// this._a = new Clipperz.Crypto.BigInt("37532428169486597638072888476611365392249575518156687476805936694442691012367", 10);
}
return this._a;
},
//-------------------------------------------------------------------------
'A': function () {
if (this._A == null) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
+ // Warning: this value should be strictly greater than zero
this._A = Clipperz.Crypto.SRP.g().powerModule(this.a(), Clipperz.Crypto.SRP.n());
-
- if (this._A.equals(0)) {
+ if (this._A.equals(0) || negative(this._A)) {
Clipperz.logError("Clipperz.Crypto.SRP.Connection: trying to set 'A' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
}
return this._A;
},
//-------------------------------------------------------------------------
's': function () {
return this._s;
},
'set_s': function(aValue) {
this._s = aValue;
},
//-------------------------------------------------------------------------
'B': function () {
return this._B;
},
'set_B': function(aValue) {
- // Warning: this value should be strictly greater than zero: how should we perform this check?
- if (! aValue.equals(0)) {
- this._B = aValue;
- } else {
+ // Warning: this value should be strictly greater than zero
+ this._B = aValue;
+ if (this._B.equals(0) || negative(this._B)) {
Clipperz.logError("Clipperz.Crypto.SRP.Connection: trying to set 'B' to 0.");
throw Clipperz.Crypto.SRP.exception.InvalidValue;
}
},
//-------------------------------------------------------------------------
'x': function () {
if (this._x == null) {
this._x = new Clipperz.Crypto.BigInt(this.stringHash(this.s().asString(16, 64) + this.P()), 16);
}
return this._x;
},
//-------------------------------------------------------------------------
'u': function () {
if (this._u == null) {
- this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.B().asString()), 16);
+ this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.A().asString() + this.B().asString()), 16);
}
return this._u;
},
//-------------------------------------------------------------------------
'S': function () {
if (this._S == null) {
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
this._S = bigint.powerModule(
- bigint.subtract(this.B(), bigint.powerModule(srp.g(), this.x(), srp.n())),
- bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
- srp.n()
+ bigint.subtract(
+ this.B(),
+ bigint.multiply(
+ Clipperz.Crypto.SRP.k(),
+ bigint.powerModule(srp.g(), this.x(), srp.n())
+ )
+ ),
+ bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
+ srp.n()
)
}
return this._S;
},
//-------------------------------------------------------------------------
'K': function () {
if (this._K == null) {
this._K = this.stringHash(this.S().asString());
}
return this._K;
},
//-------------------------------------------------------------------------
'M1': function () {
if (this._M1 == null) {
- this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
+// this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
+
+ // http://srp.stanford.edu/design.html
+ // User -> Host: M = H(H(N) xor H(g), H(I), s, A, B, K)
+
+ this._M1 = this.stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ this.stringHash(this.C()) +
+ this.s().asString() +
+ this.A().asString() +
+ this.B().asString() +
+ this.K()
+ );
+//console.log("M1", this._M1);
}
return this._M1;
},
//-------------------------------------------------------------------------
'M2': function () {
if (this._M2 == null) {
this._M2 = this.stringHash(this.A().asString(10) + this.M1() + this.K());
+//console.log("M2", this._M2);
}
return this._M2;
},
//=========================================================================
'serverSideCredentialsWithSalt': function(aSalt) {
var result;
var s, x, v;
s = aSalt;
x = this.stringHash(s + this.P());
v = Clipperz.Crypto.SRP.g().powerModule(new Clipperz.Crypto.BigInt(x, 16), Clipperz.Crypto.SRP.n());
result = {};
result['C'] = this.C();
result['s'] = s;
result['v'] = v.asString(16);
return result;
},
'serverSideCredentials': function() {
var result;
var s;
s = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
result = this.serverSideCredentialsWithSalt(s);
return result;
},
//=========================================================================
/*
'computeServerSide_S': function(b) {
var result;
var v;
var bigint;
var srp;
bigint = Clipperz.Crypto.BigInt;
srp = Clipperz.Crypto.SRP;
v = new Clipperz.Crypto.BigInt(srpConnection.serverSideCredentialsWithSalt(this.s().asString(16, 64)).v, 16);
// _S = (this.A().multiply(this.v().modPow(this.u(), this.n()))).modPow(this.b(), this.n());
result = bigint.powerModule(
diff --git a/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js b/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
index b806cb7..e5f68a8 100644
--- a/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
+++ b/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
@@ -1,87 +1,87 @@
/*
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._currentStaticConnection = null;
-
+
return this;
}
Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
//-------------------------------------------------------------------------
'isReadOnly': function () {
return this._isReadOnly;
},
//-------------------------------------------------------------------------
'shouldPayTolls': function() {
return this._shouldPayTolls;
},
//-------------------------------------------------------------------------
'data': function () {
return this._data;
},
//-------------------------------------------------------------------------
'tolls': function () {
return this._tolls;
},
//=========================================================================
'resetData': function() {
this._data = {
'users': {
'catchAllUser': {
__masterkey_test_value__: 'masterkey',
s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00',
v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
}
}
};
},
//-------------------------------------------------------------------------
'setupWithEncryptedData': function(someData) {
this._data = Clipperz.Base.deepClone(someData);
},
@@ -246,157 +246,172 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
result = this._handshake(connection, someParameters.parameters);
break;
case 'message':
this.checkToll(aFunctionName, someParameters);
result = this._message(connection, someParameters.parameters);
break;
case 'logout':
this._currentStaticConnection = null;
result = this._logout(connection, someParameters.parameters);
break;
}
this.storeConnectionForRequestWithConnectionAndResponse(aFunctionName, someParameters, connection, result);
return MochiKit.Async.succeed(result);
},
//=========================================================================
'_knock': function(aConnection, someParameters) {
var result;
result = {
toll: this.getTollForRequestType(someParameters['requestType'])
}
return result;
},
//-------------------------------------------------------------------------
'_registration': function(aConnection, 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': Clipperz.Crypto.Base.generateRandomSeed(),
'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 result;
},
//-------------------------------------------------------------------------
'_handshake': function(aConnection, someParameters) {
var result;
var nextTollRequestType;
result = {};
if (someParameters.message == "connect") {
var userData;
var randomBytes;
var v;
userData = this.data()['users'][someParameters.parameters.C];
if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
aConnection['userData'] = userData;
aConnection['C'] = someParameters.parameters.C;
} else {
aConnection['userData'] = this.data()['users']['catchAllUser'];
}
randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16);
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
- aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
+ aConnection['B'] = (Clipperz.Crypto.SRP.k().multiply(v)).add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
aConnection['A'] = someParameters.parameters.A;
result['s'] = aConnection['userData']['s'];
result['B'] = aConnection['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);
+ };
+
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
- u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16);
A = new Clipperz.Crypto.BigInt(aConnection['A'], 16);
+ u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10))).toHexString(), 16);
+ s = new Clipperz.Crypto.BigInt(aConnection['userData']['s'], 16);
S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['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) + aConnection['B'].asString(10) + K)).toHexString().slice(2);
+ M1 = stringHash(
+ "597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
+ stringHash(aConnection['C']) +
+ s.asString(10) +
+ A.asString(10) +
+ aConnection['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;
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 {
Clipperz.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
}
result = {
result: result,
toll: this.getTollForRequestType(nextTollRequestType)
}
return result;