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.

Any pointers as always appreciated.

I think I have one around here somewhere… I just have to recall which project its in.

It assesses the password strength based on an algorithm I found on the net years ago

``````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

//
//
'
' 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))
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"
``````

@Kem Tekinay has AnalyzePasswordStrength in M_String module …

M_String

Thanks both, thats saved me an afternoon

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 thats 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 thats 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’.

For Mac OS you also might want to check out SFPasswordAssistantMBS