|
@@ -15,8 +15,9 @@ module.exports = { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
function generatePassword(site, login, masterPassword, passwordProfile) { |
|
|
function generatePassword(site, login, masterPassword, passwordProfile) { |
|
|
return calcEntropy(site, login, masterPassword, passwordProfile).then(function (entropy) { |
|
|
|
|
|
return renderPassword(entropy, passwordProfile) |
|
|
|
|
|
|
|
|
var _passwordProfile = objectAssign({}, defaultPasswordProfile, passwordProfile); |
|
|
|
|
|
return calcEntropy(site, login, masterPassword, _passwordProfile).then(function (entropy) { |
|
|
|
|
|
return renderPassword(entropy, _passwordProfile); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -26,17 +27,16 @@ var defaultPasswordProfile = { |
|
|
digits: true, |
|
|
digits: true, |
|
|
symbols: true, |
|
|
symbols: true, |
|
|
length: 16, |
|
|
length: 16, |
|
|
counter: 1, |
|
|
|
|
|
|
|
|
index: 1, |
|
|
iterations: 100000, |
|
|
iterations: 100000, |
|
|
keylen: 32, |
|
|
keylen: 32, |
|
|
digest: 'sha256' |
|
|
digest: 'sha256' |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
function calcEntropy(site, login, masterPassword, passwordProfile) { |
|
|
function calcEntropy(site, login, masterPassword, passwordProfile) { |
|
|
var _passwordProfile = objectAssign({}, defaultPasswordProfile, passwordProfile); |
|
|
|
|
|
return new Promise(function (resolve, reject) { |
|
|
return new Promise(function (resolve, reject) { |
|
|
var salt = site + login + _passwordProfile.counter.toString(16); |
|
|
|
|
|
pbkdf2.pbkdf2(masterPassword, salt, _passwordProfile.iterations, _passwordProfile.keylen, _passwordProfile.digest, function (error, key) { |
|
|
|
|
|
|
|
|
var salt = site + login + passwordProfile.index.toString(16); |
|
|
|
|
|
pbkdf2.pbkdf2(masterPassword, salt, passwordProfile.iterations, passwordProfile.keylen, passwordProfile.digest, function (error, key) { |
|
|
if (error) { |
|
|
if (error) { |
|
|
reject('error in pbkdf2'); |
|
|
reject('error in pbkdf2'); |
|
|
} else { |
|
|
} else { |
|
@@ -46,7 +46,7 @@ function calcEntropy(site, login, masterPassword, passwordProfile) { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var subsetOfChars = { |
|
|
|
|
|
|
|
|
var characterSubsets = { |
|
|
lowercase: 'abcdefghijklmnopqrstuvwxyz', |
|
|
lowercase: 'abcdefghijklmnopqrstuvwxyz', |
|
|
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', |
|
|
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', |
|
|
digits: '0123456789', |
|
|
digits: '0123456789', |
|
@@ -55,22 +55,22 @@ var subsetOfChars = { |
|
|
|
|
|
|
|
|
function getSetOfCharacters(rules) { |
|
|
function getSetOfCharacters(rules) { |
|
|
if (typeof rules === 'undefined') { |
|
|
if (typeof rules === 'undefined') { |
|
|
return subsetOfChars.lowercase + subsetOfChars.uppercase + subsetOfChars.digits + subsetOfChars.symbols; |
|
|
|
|
|
|
|
|
return characterSubsets.lowercase + characterSubsets.uppercase + characterSubsets.digits + characterSubsets.symbols; |
|
|
} |
|
|
} |
|
|
var setOfChars = ''; |
|
|
var setOfChars = ''; |
|
|
rules.forEach(function (rule) { |
|
|
rules.forEach(function (rule) { |
|
|
setOfChars += subsetOfChars[rule] |
|
|
|
|
|
|
|
|
setOfChars += characterSubsets[rule]; |
|
|
}); |
|
|
}); |
|
|
return setOfChars; |
|
|
return setOfChars; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { |
|
|
function consumeEntropy(generatedPassword, quotient, setOfCharacters, maxLength) { |
|
|
if (generatedPassword.length >= maxLength) { |
|
|
if (generatedPassword.length >= maxLength) { |
|
|
return {value: generatedPassword, entropy: quotient} |
|
|
|
|
|
|
|
|
return {value: generatedPassword, entropy: quotient}; |
|
|
} |
|
|
} |
|
|
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); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function insertStringPseudoRandomly(generatedPassword, entropy, string) { |
|
|
function insertStringPseudoRandomly(generatedPassword, entropy, string) { |
|
@@ -85,24 +85,23 @@ function insertStringPseudoRandomly(generatedPassword, entropy, string) { |
|
|
function getOneCharPerRule(entropy, rules) { |
|
|
function getOneCharPerRule(entropy, rules) { |
|
|
var oneCharPerRules = ''; |
|
|
var oneCharPerRules = ''; |
|
|
rules.forEach(function (rule) { |
|
|
rules.forEach(function (rule) { |
|
|
var password = consumeEntropy('', entropy, subsetOfChars[rule], 1); |
|
|
|
|
|
|
|
|
var password = consumeEntropy('', entropy, characterSubsets[rule], 1); |
|
|
oneCharPerRules += password.value; |
|
|
oneCharPerRules += password.value; |
|
|
entropy = password.entropy; |
|
|
entropy = password.entropy; |
|
|
}); |
|
|
}); |
|
|
return {value: oneCharPerRules, entropy: entropy}; |
|
|
return {value: oneCharPerRules, entropy: entropy}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function validRules(passwordProfile) { |
|
|
|
|
|
|
|
|
function getConfiguredRules(passwordProfile) { |
|
|
return ['lowercase', 'uppercase', 'digits', 'symbols'].filter(function (rule) { |
|
|
return ['lowercase', 'uppercase', 'digits', 'symbols'].filter(function (rule) { |
|
|
return passwordProfile[rule]; |
|
|
return passwordProfile[rule]; |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function renderPassword(entropy, passwordProfile) { |
|
|
function renderPassword(entropy, passwordProfile) { |
|
|
var _passwordProfile = objectAssign({}, defaultPasswordProfile, passwordProfile); |
|
|
|
|
|
var rules = validRules(_passwordProfile); |
|
|
|
|
|
|
|
|
var rules = getConfiguredRules(passwordProfile); |
|
|
var setOfCharacters = getSetOfCharacters(rules); |
|
|
var setOfCharacters = getSetOfCharacters(rules); |
|
|
var password = consumeEntropy('', bigInt(entropy, 16), setOfCharacters, _passwordProfile.length - rules.length); |
|
|
|
|
|
|
|
|
var password = consumeEntropy('', bigInt(entropy, 16), setOfCharacters, passwordProfile.length - rules.length); |
|
|
var charactersToAdd = getOneCharPerRule(password.entropy, rules); |
|
|
var charactersToAdd = getOneCharPerRule(password.entropy, rules); |
|
|
return insertStringPseudoRandomly(password.value, charactersToAdd.entropy, charactersToAdd.value); |
|
|
return insertStringPseudoRandomly(password.value, charactersToAdd.entropy, charactersToAdd.value); |
|
|
} |
|
|
} |