Before I re-invent the wheel has anyone done a password complexity function/method, or algorithm I could use. Just adding the finishing touches to a web app and would like something to test a password and return true or false as to whether it meets defined criteria.
i.e. is it greater than 8 characters, does it contain special characters, at least one number, a capitalised letter etc.
Public Function Password_Strength(pwd As String) as Integer
Dim i As Integer
Dim j As Integer
Dim c As String
Dim cnt_upper As Integer
Dim cnt_lower As Integer
Dim cnt_numeric As Integer
Dim cnt_middle As Integer
Dim cnt_con_upper As Integer ' consecutive Uppercase letters
Dim cnt_con_lower As Integer
Dim cnt_con_numeric As Integer
Dim cnt_symbols As Integer
Dim len_pwd As Integer
Dim last_c As String
Dim score As Integer
Dim min_req As Integer
Dim repeat As Integer
Dim sFWD As String
Dim sREV As String
Dim total_score As Integer
len_pwd=Len(pwd)
cnt_upper=0
cnt_con_upper=0
cnt_lower=0
cnt_con_lower=0
cnt_numeric=0
cnt_con_numeric=0
cnt_symbols=0
cnt_middle=0
If len_pwd>0 Then
For i=1 To len_pwd
c=Mid(pwd,i,1)
If InStrB(const_UpperCase,c)>0 Then
cnt_upper=cnt_upper+1
If i>1 And InStrB(const_UpperCase,last_c)>0 Then cnt_con_upper=cnt_con_upper+1
End If
If InStrB(const_LowerCase,c)>0 Then
cnt_lower=cnt_lower+1
If i>1 And InStrB(const_LowerCase,last_c)>0 Then cnt_con_lower=cnt_con_lower+1
End If
If InStrB(const_number,c)>0 Then
cnt_numeric=cnt_numeric+1
If i>1 Then
If i<Len(pwd) Then cnt_middle=cnt_middle+1
If InStrB(const_number,last_c)>0 Then cnt_con_numeric=cnt_con_numeric+1
End If
End If
If InStrB(const_SYMBOLS,c)>0 Then
cnt_symbols=cnt_symbols+1
If i>1 And i<Len(pwd) Then cnt_middle=cnt_middle+1
End If
last_c=c
Next i
Else
Return -1
End If
//
// Additions
//
'
' Number of characters [Fail<min Warn=n/a Good=min Great>min]
'
score=(len_pwd*4)
total_score=total_score+score
'
' Uppercase Characters [Fail=0 Good=1 Great>1]
'
score=((len_pwd-cnt_upper)*2)
If cnt_upper=len_pwd Or cnt_upper=0 Then score=0
total_score=total_score+score
'
' Lowercase Characters [Fail=0 Good=1 Great>1]
'
score=((len_pwd-cnt_lower)*2)
If cnt_lower=len_pwd Or cnt_lower=0 Then score=0
total_score=total_score+score
'
' Numbers [Fail=0 Good=1 Great>1]
'
score=cnt_numeric*4
If cnt_numeric=len_pwd Or (cnt_upper+cnt_lower=0) Then score=0
total_score=total_score+score
'
' Symbols [Fail=0 Good=1 Great>1]
'
score=cnt_symbols*6
total_score=total_score+score
'
' Numbers and/or Symbols in the Middle
'
score=cnt_middle*2
total_score=total_score+score
'
' Minimum Requirements
'
min_req=0
If cnt_upper>0 Then min_req=min_req+1
If cnt_lower>0 Then min_req=min_req+1
If cnt_numeric>0 Then min_req=min_req+1
If cnt_symbols>0 Then min_req=min_req+1
score=0
If len_pwd>=min_pwd_length Then
min_req=min_req+1
min_req=Max(0,min_req)
score=min_req*2
End If
total_score=total_score+score
'
//
// Deductions
//
'
' Letters Only
'
score=0
If cnt_upper+cnt_lower=len_pwd Then score=len_pwd
total_score=total_score-score
'
' Numbers Only
'
score=0
If cnt_numeric=len_pwd Then score=len_pwd
total_score=total_score-score
'
' Repeat Characters [insensitive]
'
score=0
For i=1 To len_pwd-1
repeat=0
For j=i+1 To len_pwd
If Mid(pwd,i,1)=Mid(pwd,j,1) Then
repeat=repeat+2
End If
Next j
If repeat>0 Then score=score+(repeat*(repeat-1))
Next i
total_score=total_score-score
'
' Consecutive UpperCase Letters
'
score=0
If cnt_con_upper>0 Then score=cnt_con_upper*2
total_score=total_score-score
'
' Consecutive Lowercase Letters
'
score=0
If cnt_con_lower>0 Then score=cnt_con_lower*2
total_score=total_score-score
'
' Consecutive Numbers
'
score=0
If cnt_con_numeric>0 Then score=cnt_con_numeric*2
total_score=total_score-score
'
' Sequential Letters (3 or more)
'
repeat=0
For i=1 To Len(const_UpperCase)-3
sFWD=Mid(const_UpperCase,i,3)
sREV=reverse(sFWD)
If InStr(pwd,sfwd)>0 Or InStr(pwd,srev)>0 Then repeat=repeat+1
Next i
score=0
If repeat>0 Then score=repeat*3
total_score=total_score-score
'
' Sequential Numbers (3 or more)
'
repeat=0
For i=1 To Len(const_number)-3
sFWD=Mid(const_number,i,3)
sREV=reverse(sFWD)
If InStr(pwd,sfwd)>0 Or InStr(pwd,srev)>0 Then repeat=repeat+1
Next i
score=0
If repeat>0 Then score=repeat*3
total_score=total_score-score
'
'
'
total_SCORE=Max(0,Min(100,total_score))
Return total_SCORE
end function
Total Score is
-1 "No Password"
0 To 19 "Very Weak"
20 To 39 "Weak"
40 To 59 "Good"
60 To 79 "Strong"
80 To 100 "Very Strong"
I would recommend NOT including a strength indicator, since it really is meaningless. Common passwords will pass the test despite being weak because they are common, reused passwords cannot be tested at all, and purple monkey dishwasher is a stronger password than 1Nsecure! but strength detection would tell you the opposite. Though both are on the weaker side due to being entirely dictionary words.
These things give users a false sense of security.
The only good password is a long, random, and unique password. While thats not your crusade to fight, you might consider not giving positive reinforcement to poor password practices.
[quote=403696:@Thom McGrath]I would recommend NOT including a strength indicator, since it really is meaningless. Common passwords will pass the test despite being weak because they are common, reused passwords cannot be tested at all, and purple monkey dishwasher is a stronger password than 1Nsecure! but strength detection would tell you the opposite. Though both are on the weaker side due to being entirely dictionary words.
These things give users a false sense of security.
The only good password is a long, random, and unique password. While thats not your crusade to fight, you might consider not giving positive reinforcement to poor password practices.[/quote]
I wrote (for a customer) a Xojo class that checks to see if a password has been compromised before using the "have i been pwned API. Now this doesnt tell you if a password is strong or not, it can tell you if it is one of the ones that the hackers have out there (been pwned).
I wrote an artice about it for XDev…
And I agree with Thom that a longer password is better than one that just has upper/lower alpha & numbers & special characters.
LIked the article Scott. The method Dave provided will be fine for my purposes, its purely to ensure people don’t even start with an easy password. I like phrases, easier to remember, long and complex, but most users prefer something short and snappy - which hence, compromises their security and they need to be ‘warned off’.