--Boundary-00=_ViIQCRLS80rDHFf Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, its great to see that there is now a passwort strength meter in KDE, because IMHO bad passwords are the most common security problem. But in my opinion the code which calculates the password strength has some shortcomings. It doesn't check for stupid combinations and the repetition of strings. So i worked on an algorithm to address this issues. It works as follows: - A character is put in one category (lowercase,uppercase,digit,other) - Two succeeding characters are evaluated. Every combination of categories has a special rating (e.g. digit following a digit => rating=4; digit following a uppercase => rating=10) - The password strength is the sum of all the ratings. Since combinations which are thought to be strange have a higher rating, the user is rewarded for using them. Additionally there is a check for simple combinations: - The ascii-code-difference of two succeeding characters is calculated and stored in a list. - If the current difference is in the list, the rating is set to zero. Here are two examples of bad passwords which get a high rating from the Firefox code, but a low with the new proposal: password Firefox new Proposal ---------------------------------- 111111 60 4 a1.a1. 80 32 I would be happy if i could enhance KDE with this code, even if it is only a tiny detail. PJ --Boundary-00=_ViIQCRLS80rDHFf Content-Type: text/x-diff; charset="us-ascii"; name="kpassdlg.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kpassdlg.diff" --- orginal/kpassdlg.cpp 2005-03-10 21:34:19.000000000 +0100 +++ kpassdlg.cpp 2005-03-22 21:03:16.000000000 +0100 @@ -616,30 +616,81 @@ } // Password strength calculator - // Based on code in the Master Password dialog in Firefox - // (pref-masterpass.js) - // Original code triple-licensed under the MPL, GPL, and LGPL - // so is license-compatible with this file const double lengthFactor = d->reasonablePasswordLength / 8.0; - - int pwlength = (int) (pass.length() / lengthFactor); - if (pwlength > 5) pwlength = 5; - - const QRegExp numRxp("[0-9]", true, false); - int numeric = (int) (pass.contains(numRxp) / lengthFactor); - if (numeric > 3) numeric = 3; - - const QRegExp symbRxp("\\W", false, false); - int numsymbols = (int) (pass.contains(symbRxp) / lengthFactor); - if (numsymbols > 3) numsymbols = 3; + const char* pw = m_pEdit->password(); + + enum Category{Lower=0,Upper,Digit,Other,Inval}; - const QRegExp upperRxp("[A-Z]", true, false); - int upper = (int) (pass.contains(upperRxp) / lengthFactor); - if (upper > 3) upper = 3; + // prev is = L U D O I + const int rating[5][5] = { { 6, 8,10,11, 0 }, // current is Lower + { 8, 7,10,11, 0 }, // current is Upper + { 10,10, 4,11, 0 }, // current is Digit + { 11,11,11, 7, 0 }, // current is Other + { 0, 0, 0, 0, 0 } }; // current is Inval + + int maximumCharPerCategory[5] = {5,5,5,5,5}; + + bool pastDiff[256]; + for(int i=0 ; i<=255 ; i++ ){ + pastDiff[i] = false; + } + + Category currentCat = Inval; + Category prevCat = Inval; + + int pwlen = strlen(pw); + int pwstrength = 0; + unsigned char prevASCII = 205; + + + for (int i=0; i < pwlen ;i++) //for each character + { + currentCat = Other; + if (( pw[i] >= 48 ) and (pw[i] <= 57)) {currentCat = Digit;}; + if (( pw[i] >= 65 ) and (pw[i] <= 90)) {currentCat = Upper;}; + if (( pw[i] >= 97 ) and (pw[i] <=122)) {currentCat = Lower;}; + + int charRating = rating[currentCat][prevCat]; + + if ( maximumCharPerCategory[currentCat] == 0 ) { + charRating = 0; + } + else { + maximumCharPerCategory[currentCat]--; + } + + unsigned char diff = pw[i] - prevASCII; + if (pastDiff[diff]) { + charRating = 0; + } + else { + pastDiff[diff] = true; + } + + pwstrength += charRating; + + prevCat = currentCat; + prevASCII = pw[i]; + } + + // delete variables + currentCat = Inval; + prevCat = Inval; + pwlen = 0; + prevASCII = 205; + + for(int i=0 ; i<=255 ; i++ ){ + pastDiff[i] = false; + } + + for(int i=0 ; i<5 ; i++ ){ + maximumCharPerCategory[i]=0; + } - int pwstrength=((pwlength*10)-20) + (numeric*10) + (numsymbols*15) + (upper*10); + + pwstrength = (int)(pwstrength / lengthFactor); if ( pwstrength < 0 ) { pwstrength = 0; @@ -689,7 +740,7 @@ return d->maximumPasswordLength; } void KPasswordDialog::setReasonablePasswordLength(int reasonableLength) { --Boundary-00=_ViIQCRLS80rDHFf--