Subversion Repositories pub

Compare Revisions

No changes between revisions

Regard whitespace Rev 193 → Rev 194

/relevation/branches/1.1/devtools/checkpw.py
0,0 → 1,105
#!/usr/bin/env python
 
"""
Simplistic Password Strength Checker.
"""
 
# Based on
# <http://www.geekwisdom.com/dyn/passwdmeter>
# |-> <http://www.geekwisdom.com/js/passwordmeter.js>
# (this is mostly based on the scoring system explained there,
# and not on the actual implementation)
 
import re
import string
import sys
 
WEAK_THRESHOLD = 16
MEDIOCRE_THRESHOLD = 25
STRONG_THRESHOLD = 35
VERY_STRONG_THRESHOLD = 45
 
def check(pw):
'''
check(str) -> ( int score, str strength category, str description)
'''
score = 0
verdict = 'weak'
log = ''
# Password length
length = len(pw)
if length == 0:
return ( 0, 'weak', 'empty password' )
if length < 5:
score += 3
elif length < 8:
score += 6
elif length < 16:
score += 12
else:
score += 18
log += '%d points for length (%d)\n' % (score, length)
# Letters
locase = re.search('[a-z]', pw)
upcase = re.search('[A-Z]', pw)
if (locase and upcase):
score += 7
log += '7 points for mixed case\n'
elif locase:
score += 5
log += '5 points for all-lowercase letters\n'
elif upcase:
score += 5
log += '5 points for all-uppercase letters\n'
else: # No letters at all
pass
# Numbers
hasnums = re.search('\d', pw)
if hasnums and re.search('\d.*\d.*\d', pw):
score += 7
log += '7 points for at least three numbers\n'
elif hasnums:
score += 5
log += '5 points for at least one number\n'
# Special Characters
sch = string.punctuation
hasspecial = re.search('[%s]' % sch, pw)
if hasspecial and re.search('[%s].*[%s]' % ( sch, sch), pw):
score += 10
log += '10 points for at least two special characters\n'
elif hasspecial:
score += 5
log += '5 points for at least one special character\n'
# Combos
hasletters = re.search('([a-z]|[A-Z])', pw)
if hasnums and hasletters:
score += 1
log += '1 combo point for mixed letters and numbers\n'
if hasspecial:
score += 2
log += '2 combo points for mixed letters, numbers and special characters\n'
if upcase and locase:
score += 2
log += '2 combo point for mixed case letters, numbers and special characters'
# Verdict
if score < WEAK_THRESHOLD:
verdict = 'very weak'
elif score < MEDIOCRE_THRESHOLD:
verdict = 'weak'
elif score < STRONG_THRESHOLD:
verdict = 'mediocre'
elif score < VERY_STRONG_THRESHOLD:
verdict = 'strong'
else:
verdict = 'stronger'
 
return ( score, verdict, log )
 
if __name__ == '__main__':
for candidate in sys.argv[1:]:
( score, verdict, descr ) = check(candidate)
print '%s: %s\t%s' % ( candidate, score, verdict )
sys.stderr.write(descr)
 
# vim:set ts=4 et ai: #
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/relevation/branches/1.1/devtools/genpw.py
14,6 → 14,12
import locale
import sys
 
try:
import checkpw
DO_CHECK=True
except ImportError:
DO_CHECK=False
 
DEFAULT_RESULTS = 20
DEFAULT_LENGTH = 8
#Letters and digits are repeated to favour them
22,17 → 28,51
DEFAULT_CSET = FAVOURED_SET * 8 + STDSET
 
REJECTS_SET = [ 'l', '1', 'I', '0', 'O' ] # FIXME: What else?
DEFAULT_FORCE = '*' # Symbolic
 
def pwgen(length=DEFAULT_LENGTH, possible=DEFAULT_CSET, reject_ambiguous=False):
def pwgen(length=DEFAULT_LENGTH, possible=DEFAULT_CSET,
reject_ambiguous=False, force=DEFAULT_FORCE):
'''
pwgen(int, str, bool, [ str, str, ...]) -> str
 
Generate a password.
length - Password length
possible - List of characters from where to pick
reject_ambiguous - Reject characters that can be hard to tell from each other (e.g. 1 vs l vs I)
force - List of forcible sets. Force at least one character of each set.
'''
pw = ''
rejects = []
LENGTH = length
if reject_ambiguous:
rejects = REJECTS_SET
if force == DEFAULT_FORCE:
force = [ string.lowercase, string.uppercase, string.digits ]
if type(force) != list:
raise ValueError('force must be a list of strings')
def pick_one(cset):
'''
Return a random character from cset
'''
c = random.choice(cset)
while c in rejects:
c = random.choice(cset)
return c
# Forcible includes
for cset in force:
pw += pick_one(cset)
length -= 1
for i in range(length):
pick = random.choice(possible)
while pick in rejects:
pick = random.choice(possible)
pw += pick
# Re-mix order (randomize forced-characters' position)
if len(pw) > LENGTH:
pw = pw[0:LENGTH]
l = list(pw)
random.shuffle(l)
pw = ''.join(l)
return pw
 
def main(argv):
40,6 → 80,7
length = DEFAULT_LENGTH
cset = DEFAULT_CSET
reject_ambiguous = False
secure = False # When True, reject mediocre passwords and below
 
# No need to use getopt or anything like it
positional = []
46,6 → 87,10
for arg in argv:
if arg in ( '-B', '--ambiguous' ):
reject_ambiguous = True
elif arg in ( '-s', '--secure' ):
if not DO_CHECK:
raise EnvironmentError('Can\'t generate secure-only password without checkpw.py')
secure = True
else:
positional.append(arg)
try:
57,10 → 102,23
sys.stderr.write('Usage: pwgen [-B] [length] [num pw]\n');
sys.exit(2);
 
def newpw():
return pwgen(length=length, reject_ambiguous=reject_ambiguous)
 
for i in range(rounds):
print pwgen(length=length, reject_ambiguous=reject_ambiguous)
pw = newpw()
if DO_CHECK:
( score, verdict, _ ) = checkpw.check(pw)
while score < checkpw.STRONG_THRESHOLD:
pw = newpw()
( score, verdict, _ ) = checkpw.check(pw)
print '%s\t%d\t%s' % ( pw, score, verdict)
#print _
else:
print pw
 
if __name__ == '__main__':
locale.setlocale(locale.LC_ALL, 'C')
main(sys.argv[1:])
 
# vim:set ts=4 et ai: #
Property changes:
Added: svn:executable
+*
\ No newline at end of property