@@ -14,9 +14,10 @@ module.exports = { | |||
_getCharType: _getCharType, | |||
_getPasswordChar: _getPasswordChar, | |||
_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) { | |||
@@ -2,7 +2,21 @@ var Promise = require("bluebird"); | |||
var pbkdf2 = require('pbkdf2'); | |||
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) { | |||
var salt = site + login + passwordProfile.counter.toString(16); | |||
var iterations = passwordProfile.iterations || 100000; | |||
@@ -15,10 +29,10 @@ exports.calcEntropy = function (site, login, masterPassword, passwordProfile) { | |||
resolve(key.toString('hex')); | |||
} | |||
}); | |||
}) | |||
}; | |||
}); | |||
} | |||
exports.getSetOfCharacters = function (passwordProfile) { | |||
function _getSetOfCharacters(passwordProfile) { | |||
var subsetOfCharacters = { | |||
lowercase: 'abcdefghijklmnopqrstuvwxyz', | |||
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', | |||
@@ -37,19 +51,19 @@ exports.getSetOfCharacters = function (passwordProfile) { | |||
} | |||
}); | |||
return setOfCharacters; | |||
}; | |||
} | |||
function consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { | |||
function _consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { | |||
if (generatedPassword.length >= maxLength) { | |||
return generatedPassword | |||
} | |||
var longDivision = quotient.divmod(setOfCharacters.length); | |||
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 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; | |||
describe('LessPass', function () { | |||
describe('LessPass v2', function () { | |||
describe('entropy', function () { | |||
it('calc entropy pbkdf2 with default params (100000 iterations, 32 bytes length, sha256 digest)', function () { | |||
this.timeout(10000); | |||
@@ -12,7 +12,7 @@ describe('LessPass', function () { | |||
}; | |||
return LessPass._calcEntropy(site, login, masterPassword, passwordProfile).then(function (entropy) { | |||
assert.equal('dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e', entropy); | |||
}) | |||
}); | |||
}); | |||
it('calc entropy with different options (8192 iterations, 16 bytes length, sha512 digest)', function () { | |||
@@ -1,6 +1,6 @@ | |||
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 () { | |||
var entropy = 'dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e'; | |||
var setOfCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | |||
@@ -1,6 +1,6 @@ | |||
var assert = chai.assert; | |||
describe('LessPass', function () { | |||
describe('LessPass v2', function () { | |||
describe('set of characters', function () { | |||
it('get default set of characters', function () { | |||
var setOfCharacters = LessPass._getSetOfCharacters(); | |||