@@ -14,9 +14,10 @@ module.exports = { | |||||
_getCharType: _getCharType, | _getCharType: _getCharType, | ||||
_getPasswordChar: _getPasswordChar, | _getPasswordChar: _getPasswordChar, | ||||
_createHmac: _createHmac, | _createHmac: _createHmac, | ||||
_calcEntropy: v2.calcEntropy, | |||||
_getSetOfCharacters: v2.getSetOfCharacters, | |||||
_renderPassword: v2.renderPassword, | |||||
generatePassword: v2.generatePassword, | |||||
_calcEntropy: v2._calcEntropy, | |||||
_getSetOfCharacters: v2._getSetOfCharacters, | |||||
_renderPassword: v2._renderPassword, | |||||
}; | }; | ||||
function _encryptLogin(login, masterPassword, options) { | function _encryptLogin(login, masterPassword, options) { | ||||
@@ -2,7 +2,21 @@ var Promise = require("bluebird"); | |||||
var pbkdf2 = require('pbkdf2'); | var pbkdf2 = require('pbkdf2'); | ||||
var bigInt = require("big-integer"); | var bigInt = require("big-integer"); | ||||
exports.calcEntropy = function (site, login, masterPassword, passwordProfile) { | |||||
exports.generatePassword = generatePassword; | |||||
function generatePassword(site, login, masterPassword, passwordProfile) { | |||||
return _calcEntropy(site, login, masterPassword, passwordProfile).then(function (entropy) { | |||||
var setOfCharacters = _getSetOfCharacters(passwordProfile); | |||||
return _renderPassword(entropy, setOfCharacters, passwordProfile) | |||||
}); | |||||
} | |||||
exports._calcEntropy = _calcEntropy; | |||||
exports._getSetOfCharacters = _getSetOfCharacters; | |||||
exports._renderPassword = _renderPassword; | |||||
function _calcEntropy(site, login, masterPassword, passwordProfile) { | |||||
return new Promise(function (resolve, reject) { | return new Promise(function (resolve, reject) { | ||||
var salt = site + login + passwordProfile.counter.toString(16); | var salt = site + login + passwordProfile.counter.toString(16); | ||||
var iterations = passwordProfile.iterations || 100000; | var iterations = passwordProfile.iterations || 100000; | ||||
@@ -15,10 +29,10 @@ exports.calcEntropy = function (site, login, masterPassword, passwordProfile) { | |||||
resolve(key.toString('hex')); | resolve(key.toString('hex')); | ||||
} | } | ||||
}); | }); | ||||
}) | |||||
}; | |||||
}); | |||||
} | |||||
exports.getSetOfCharacters = function (passwordProfile) { | |||||
function _getSetOfCharacters(passwordProfile) { | |||||
var subsetOfCharacters = { | var subsetOfCharacters = { | ||||
lowercase: 'abcdefghijklmnopqrstuvwxyz', | lowercase: 'abcdefghijklmnopqrstuvwxyz', | ||||
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', | uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', | ||||
@@ -37,19 +51,19 @@ exports.getSetOfCharacters = function (passwordProfile) { | |||||
} | } | ||||
}); | }); | ||||
return setOfCharacters; | return setOfCharacters; | ||||
}; | |||||
} | |||||
function consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { | |||||
function _consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { | |||||
if (generatedPassword.length >= maxLength) { | if (generatedPassword.length >= maxLength) { | ||||
return generatedPassword | return generatedPassword | ||||
} | } | ||||
var longDivision = quotient.divmod(setOfCharacters.length); | var longDivision = quotient.divmod(setOfCharacters.length); | ||||
generatedPassword += setOfCharacters[longDivision.remainder]; | generatedPassword += setOfCharacters[longDivision.remainder]; | ||||
return consumeEntropy(generatedPassword, longDivision.quotient, setOfCharacters, maxLength) | |||||
return _consumeEntropy(generatedPassword, longDivision.quotient, setOfCharacters, maxLength) | |||||
} | } | ||||
exports.renderPassword = function (entropy, setOfCharacters, passwordProfile) { | |||||
function _renderPassword(entropy, setOfCharacters, passwordProfile) { | |||||
var _passwordProfile = passwordProfile !== undefined ? passwordProfile : {}; | var _passwordProfile = passwordProfile !== undefined ? passwordProfile : {}; | ||||
var length = _passwordProfile.length || 14; | var length = _passwordProfile.length || 14; | ||||
return consumeEntropy('', bigInt(entropy, 16), setOfCharacters, length); | |||||
}; | |||||
return _consumeEntropy('', bigInt(entropy, 16), setOfCharacters, length); | |||||
} |
@@ -0,0 +1,58 @@ | |||||
var assert = chai.assert; | |||||
describe('LessPass v2', function () { | |||||
describe('API', function () { | |||||
it('render password', function () { | |||||
var site = 'example.org'; | |||||
var login = 'contact@example.org'; | |||||
var masterPassword = 'password'; | |||||
var passwordProfile = { | |||||
iterations: 100000, | |||||
lowercase: true, | |||||
uppercase: true, | |||||
digits: true, | |||||
symbols: false, | |||||
length: 14, | |||||
counter: 1 | |||||
}; | |||||
return LessPass.generatePassword(site, login, masterPassword, passwordProfile).then(function (generatedPassword) { | |||||
assert.equal('y5m7Ctw2695ksh', generatedPassword); | |||||
}); | |||||
}); | |||||
it('render password only digit', function () { | |||||
var site = 'example.org'; | |||||
var login = 'contact@example.org'; | |||||
var masterPassword = 'password'; | |||||
var passwordProfile = { | |||||
iterations: 100000, | |||||
lowercase: false, | |||||
uppercase: false, | |||||
digits: true, | |||||
symbols: false, | |||||
length: 6, | |||||
counter: 1 | |||||
}; | |||||
return LessPass.generatePassword(site, login, masterPassword, passwordProfile).then(function (generatedPassword) { | |||||
assert.equal('874236', generatedPassword); | |||||
}); | |||||
}); | |||||
it('render password no number', function () { | |||||
var site = 'example.org'; | |||||
var login = 'contact@example.org'; | |||||
var masterPassword = 'password'; | |||||
var passwordProfile = { | |||||
iterations: 100000, | |||||
lowercase: true, | |||||
uppercase: true, | |||||
digits: false, | |||||
symbols: true, | |||||
length: 14, | |||||
counter: 1 | |||||
}; | |||||
return LessPass.generatePassword(site, login, masterPassword, passwordProfile).then(function (generatedPassword) { | |||||
assert.equal("s>{F}wN/-fmMX?", generatedPassword); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
@@ -1,6 +1,6 @@ | |||||
var assert = chai.assert; | var assert = chai.assert; | ||||
describe('LessPass', function () { | |||||
describe('LessPass v2', function () { | |||||
describe('entropy', function () { | describe('entropy', function () { | ||||
it('calc entropy pbkdf2 with default params (100000 iterations, 32 bytes length, sha256 digest)', function () { | it('calc entropy pbkdf2 with default params (100000 iterations, 32 bytes length, sha256 digest)', function () { | ||||
this.timeout(10000); | this.timeout(10000); | ||||
@@ -12,7 +12,7 @@ describe('LessPass', function () { | |||||
}; | }; | ||||
return LessPass._calcEntropy(site, login, masterPassword, passwordProfile).then(function (entropy) { | return LessPass._calcEntropy(site, login, masterPassword, passwordProfile).then(function (entropy) { | ||||
assert.equal('dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e', entropy); | assert.equal('dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e', entropy); | ||||
}) | |||||
}); | |||||
}); | }); | ||||
it('calc entropy with different options (8192 iterations, 16 bytes length, sha512 digest)', function () { | it('calc entropy with different options (8192 iterations, 16 bytes length, sha512 digest)', function () { | ||||
@@ -1,6 +1,6 @@ | |||||
var assert = chai.assert; | var assert = chai.assert; | ||||
describe('LessPass', function () { | |||||
describe('LessPass v2', function () { | |||||
it('render password use remainder of long division beetween entropy and set of chars length as an index ', function () { | it('render password use remainder of long division beetween entropy and set of chars length as an index ', function () { | ||||
var entropy = 'dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e'; | var entropy = 'dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e'; | ||||
var setOfCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | var setOfCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | ||||
@@ -1,6 +1,6 @@ | |||||
var assert = chai.assert; | var assert = chai.assert; | ||||
describe('LessPass', function () { | |||||
describe('LessPass v2', function () { | |||||
describe('set of characters', function () { | describe('set of characters', function () { | ||||
it('get default set of characters', function () { | it('get default set of characters', function () { | ||||
var setOfCharacters = LessPass._getSetOfCharacters(); | var setOfCharacters = LessPass._getSetOfCharacters(); | ||||