Skip to content

Instantly share code, notes, and snippets.

@MetroWind
Created December 23, 2011 18:25
Show Gist options
  • Save MetroWind/1514997 to your computer and use it in GitHub Desktop.
Save MetroWind/1514997 to your computer and use it in GitHub Desktop.
Calculate password strength.
# -*- coding: utf-8; -*-
# Calculate password strength. Algorithm is based on the
# Wolfram|Alpha’s, without dictionary and “extra critira”.
#
# Darksair
# Usage: Strength = pwStrength(password).
import re
def findSeqChar(CharLocs, src):
"""Find all sequential chars in string `src'. Only chars in
`CharLocs' are considered. `CharLocs' is a list of numbers. For
example if `CharLocs' is [0,2,3], then only src[2:3] is a possible
substring with sequential chars.
"""
AllSeqChars = []
i = 0
SeqChars = []
while i < len(CharLocs) - 1:
if CharLocs[i + 1] - CharLocs[i] == 1 and \
ord(src[CharLocs[i+1]]) - ord(src[CharLocs[i]]) == 1:
# We find a pair of sequential chars!
if not SeqChars:
SeqChars = [src[CharLocs[i]], src[CharLocs[i+1]]]
else:
SeqChars.append(src[CharLocs[i+1]])
else:
if SeqChars:
AllSeqChars.append(SeqChars)
SeqChars = []
i += 1
if SeqChars:
AllSeqChars.append(SeqChars)
return AllSeqChars
def pwStrength(pw):
"""Wolfram|Alpha algorithm without dictionary and “extra critira”.
"""
Score = 0
Length = len(pw)
Score += Length * 4
# print("Length score: {}".format(Score))
NUpper = 0
NLower = 0
NNum = 0
NSymbol = 0
LocUpper = []
LocLower = []
LocNum = []
LocSymbol = []
CharDict = {}
for i in range(Length):
Ch = pw[i]
Code = ord(Ch)
if Code >= 48 and Code <= 57:
NNum += 1
LocNum.append(i)
elif Code >= 65 and Code <= 90:
NUpper += 1
LocUpper.append(i)
elif Code >= 97 and Code <= 122:
NLower += 1
LocLower.append(i)
else:
NSymbol += 1
LocSymbol.append(i)
if not Ch in CharDict:
CharDict[Ch] = 1
else:
CharDict[Ch] += 1
if NUpper != Length and NLower != Length:
if NUpper != 0:
Score += (Length - NUpper) * 2
# print("Upper case score:", (Length - NUpper) * 2)
if NLower != 0:
Score += (Length - NLower) * 2
# print("Lower case score:", (Length - NLower) * 2)
if NNum != Length:
Score += NNum * 4
# print("Number score:", NNum * 4)
Score += NSymbol * 6
# print("Symbol score:", NSymbol * 6)
# Middle number or symbol
Score += len([i for i in LocNum if i != 0 and i != Length - 1]) * 2
# print("Middle number score:", len([i for i in LocNum if i != 0 and i != Length - 1]) * 2)
Score += len([i for i in LocSymbol if i != 0 and i != Length - 1]) * 2
# print("Middle symbol score:", len([i for i in LocSymbol if i != 0 and i != Length - 1]) * 2)
# Letters only?
if NUpper + NLower == Length:
Score -= Length
# print("Letter only:", -Length)
if NNum == Length:
Score -= Length
# print("Number only:", -Length)
# Repeating chars
Repeats = 0
for Ch in CharDict:
if CharDict[Ch] > 1:
Repeats += CharDict[Ch] - 1
if Repeats > 0:
Score -= int(Repeats / (Length - Repeats)) + 1
# print("Repeating chars:", -int(Repeats / (Length - Repeats)) - 1)
if Length > 2:
# Consequtive letters
for MultiLowers in re.findall(''.join(["[a-z]{2,", str(Length), '}']), pw):
Score -= (len(MultiLowers) - 1) * 2
# print("Consequtive lowers:", -(len(MultiLowers) - 1) * 2)
for MultiUppers in re.findall(''.join(["[A-Z]{2,", str(Length), '}']), pw):
Score -= (len(MultiUppers) - 1) * 2
# print("Consequtive uppers:", -(len(MultiUppers) - 1) * 2)
# Consequtive numbers
for MultiNums in re.findall(''.join(["[0-9]{2,", str(Length), '}']), pw):
Score -= (len(MultiNums) - 1) * 2
# print("Consequtive numbers:", -(len(MultiNums) - 1) * 2)
# Sequential letters
LocLetters = (LocUpper + LocLower)
LocLetters.sort()
for Seq in findSeqChar(LocLetters, pw.lower()):
if len(Seq) > 2:
Score -= (len(Seq) - 2) * 2
# print("Sequential letters:", -(len(Seq) - 2) * 2)
# Sequential numbers
for Seq in findSeqChar(LocNum, pw.lower()):
if len(Seq) > 2:
Score -= (len(Seq) - 2) * 2
# print("Sequential numbers:", -(len(Seq) - 2) * 2)
return Score
@MetroWind
Copy link
Author

Consider it under WTFPL :-).

@xrstf
Copy link

xrstf commented Jun 13, 2012

Perfect. :-) My PHP port is here: https://gist.github.com/2926619 (for anyone interested).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment