[Fun] Help me improve my password strength algorithm
Posted: Thu Jul 13, 2006 11:45 am
Totally unfinished but once I start to get meaninful values out of passwordChecker.check() I can do the rest really quickly.
Basically it's supposed to score a password based upon length, case changes, numbers/letters, special chars. It would then update a little gauge as the user types in the password box.
In my check() method I increment the value the passwordChecker.points by multiplying the points given in the criteria by a factor determined by the frequency at which they occur in the string. It's halfway to working but still a little erratic.
Anybody fancy chipping in some ideas?
Basically it's supposed to score a password based upon length, case changes, numbers/letters, special chars. It would then update a little gauge as the user types in the password box.
In my check() method I increment the value the passwordChecker.points by multiplying the points given in the criteria by a factor determined by the frequency at which they occur in the string. It's halfway to working but still a little erratic.
Anybody fancy chipping in some ideas?
Code: Select all
<script type="text/javascript">
<!-- Hide me from older browsers
/**
* Checks the strength of a password
* based upon it's length and combination of characters
*/
function strengthChecker(outputId)
{
/**
* Id of the node we want to show output in
* @var string ID
* @private
*/
var elementId = outputId;
/**
* An internal timeout. Gets used in loading
* ... possibly pointless.
* @var timeout
* @private
*/
var tm = 0;
/**
* Passwords are given a strength score
* @var float score
* @private
*/
var score = false;
/**
* The actual DOM node for the guage we append
* to elementId
* @var node gauge
* @private
*/
var gaugeNode;
/**
* The weight given for the various strength enhancers
* @var array (float) points
* @private
*/
var criteriaPoints = new Array();
criteriaPoints['Case'] = 2;
criteriaPoints['Length'] = 0.5;
criteriaPoints['SpecialChars'] = 7;
criteriaPoints['AlphaNum'] = 2;
/**
* Does the initial loading of the password gauge
* upon instantiation if the page is idle
* @return void
* @private
*/
var load = function()
{
//The DOM tree may not have finished building yet
if (document.getElementById(elementId))
{
if (score === false) updateOutput();
if (tm) window.clearTimeout(tm);
}
else //If the element doesn't exist, look again in 200ms
{
tm = window.setTimeout(function() { load(); }, 200);
}
}
/**
* Update what is displayed for the gauge at elementId
* @return void
* @private
*/
var updateOutput = function()
{
//
}
/**
* Reads a new password and then gives it a score
* The password gauge is then updated
* @param string password value
* @return float score
*/
this.check = function(v)
{
score = 0;
//Score based upon length
score += v.length * criteriaPoints['Length'];
var lower = 0;
var upper = 0;
var numbers = 0;
var specialChars = 0;
var lettersOnly = '';
var numbersOnly = '';
var charsOnly = '';
for (var i = 0; i < v.length; i++)
{
var letter = v.substr(i, 1);
if (letter.match(/[a-z]/))
{
lettersOnly += letter;
lower++;
}
else if (letter.match(/[A-Z]/))
{
lettersOnly += letter;
upper++;
}
else if (letter.match(/\d/))
{
numbersOnly += letter;
numbers++;
}
else if (letter.match(/[\W\-\. ]/))
{
chars += letter;
specialChars++;
}
}
//Points based upon case change
var caseDiff = Math.abs(upper - lower);
score += parseFloat((lettersOnly.length - caseDiff) * criteriaPoints['Case']);
//Alpha Numeric Points
var alphaNumDiff = Math.abs(upper+lower - numbers);
score += parseFloat(((lettersOnly.length + numbersOnly.length) - alphaNumDiff) * criteriaPoints['AlphaNum']);
//Special Character Points
score += parseFloat(specialChars * criteriaPoints['SpecialChars']);
//Now update the gauge
updateOutput();
return score;
}
/**
* Allow the user to change the points weightings
* @param string criteria (See criteriaPoints)
* @param float points
* @return bool successful
*/
this.setPoints = function(criteria, pnts)
{
if (criteriaPoints[criteria])
{
criteriaPoints[criteria] = parseFloat(pnts);
return true;
}
else return false;
}
//At end of instantiation load the gauge
load();
}
var pw = new strengthChecker('pw_gauge');
//I'm just using this to debug
function displayValue(v)
{
document.getElementById('dummy').value = v;
}
// -->
</script>
Password: <input type="password" name="pass" onkeyup="displayValue(pw.check(this.value));" />
<div id="pw_gauge"></div>
<!-- Debug only! -->
<br />
Score: <input type="text" id="dummy" value="" />