Utilities/PasswordChecker.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 2525
8b507a9a2d40
parent 2997
7f0ef975da9e
child 3060
5883ce99ee12
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
2 2
3 # Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 5
6 """ 6 """
7 Module implementing a checker for password strength 7 Module implementing a checker for password strength.
8 """ 8 """
9 9
10 from __future__ import unicode_literals # __IGNORE_WARNING__ 10 from __future__ import unicode_literals # __IGNORE_WARNING__
11 11
12 import re 12 import re
84 84
85 # how much redundancy is permitted, if the password is 85 # how much redundancy is permitted, if the password is
86 # long enough. we will skip the redudancy penalty if this 86 # long enough. we will skip the redudancy penalty if this
87 # number is not exceeded (meaning redundancy < this number) 87 # number is not exceeded (meaning redundancy < this number)
88 self.redundancy = { 88 self.redundancy = {
89 "value": 1, # 1 means, not double characters, default to start 89 "value": 1, # 1 means, not double characters,
90 "permitted": 2.0, # 2 means, in average every character can occur twice 90 # default to start
91 "permitted": 2.0, # 2 means, in average every character
92 # can occur twice
91 "status": self.Status_Failed, 93 "status": self.Status_Failed,
92 "rating": 0, 94 "rating": 0,
93 } 95 }
94 96
95 # number of uppercase letters, such as A-Z 97 # number of uppercase letters, such as A-Z
316 uniqueCharacters.append(password[index1]) 318 uniqueCharacters.append(password[index1])
317 319
318 # calculate a redundancy number 320 # calculate a redundancy number
319 self.redundancy["value"] = len(password) / len(uniqueCharacters) 321 self.redundancy["value"] = len(password) / len(uniqueCharacters)
320 322
321 # Check for sequential alpha string patterns (forward and reverse) but only, 323 # Check for sequential alpha string patterns (forward and reverse)
322 # if the string has already a length to check for, does not make sense to check 324 # but only, if the string has already a length to check for, does
323 # the password "ab" for the sequential data "abc" 325 # not make sense to check the password "ab" for the sequential data
326 # "abc"
324 lowercasedPassword = password.lower() 327 lowercasedPassword = password.lower()
325 328
326 if self.passwordLength["count"] >= self.sequentialLetters["length"]: 329 if self.passwordLength["count"] >= self.sequentialLetters["length"]:
327 for index in range(len(self.sequentialLetters["data"]) - \ 330 for index in range(len(self.sequentialLetters["data"]) - \
328 self.sequentialLetters["length"] + 1): 331 self.sequentialLetters["length"] + 1):
348 351
349 # Check common keyboard patterns 352 # Check common keyboard patterns
350 patternsMatched = [] 353 patternsMatched = []
351 if self.passwordLength["count"] >= self.keyboardPatterns["length"]: 354 if self.passwordLength["count"] >= self.keyboardPatterns["length"]:
352 for pattern in self.keyboardPatterns["data"]: 355 for pattern in self.keyboardPatterns["data"]:
353 for index in range(len(pattern) - self.keyboardPatterns["length"] + 1): 356 for index in range(
354 fwd = pattern[index:index + self.keyboardPatterns["length"]] 357 len(pattern) - self.keyboardPatterns["length"] + 1):
358 fwd = pattern[index:index +
359 self.keyboardPatterns["length"]]
355 rev = self.__strReverse(fwd) 360 rev = self.__strReverse(fwd)
356 if lowercasedPassword.find(fwd) != -1: 361 if lowercasedPassword.find(fwd) != -1:
357 if fwd not in patternsMatched: 362 if fwd not in patternsMatched:
358 self.keyboardPatterns["count"] += 1 363 self.keyboardPatterns["count"] += 1
359 patternsMatched.append(fwd) 364 patternsMatched.append(fwd)
364 369
365 # Try to find repeated sequences of characters. 370 # Try to find repeated sequences of characters.
366 if self.passwordLength["count"] >= self.repeatedSequences["length"]: 371 if self.passwordLength["count"] >= self.repeatedSequences["length"]:
367 for index in range(len(lowercasedPassword) - \ 372 for index in range(len(lowercasedPassword) - \
368 self.repeatedSequences["length"] + 1): 373 self.repeatedSequences["length"] + 1):
369 fwd = lowercasedPassword[index:index + self.repeatedSequences["length"]] 374 fwd = lowercasedPassword[
375 index:index + self.repeatedSequences["length"]]
370 if lowercasedPassword.find( 376 if lowercasedPassword.find(
371 fwd, index + self.repeatedSequences["length"]) != -1: 377 fwd, index + self.repeatedSequences["length"]) != -1:
372 self.repeatedSequences["count"] += 1 378 self.repeatedSequences["count"] += 1
373 379
374 # Try to find mirrored sequences of characters. 380 # Try to find mirrored sequences of characters.
375 if self.passwordLength["count"] >= self.mirroredSequences["length"]: 381 if self.passwordLength["count"] >= self.mirroredSequences["length"]:
376 for index in range(len(lowercasedPassword) - \ 382 for index in range(len(lowercasedPassword) - \
377 self.mirroredSequences["length"] + 1): 383 self.mirroredSequences["length"] + 1):
378 fwd = lowercasedPassword[index:index + self.mirroredSequences["length"]] 384 fwd = lowercasedPassword[
385 index:index + self.mirroredSequences["length"]]
379 rev = self.__strReverse(fwd) 386 rev = self.__strReverse(fwd)
380 if lowercasedPassword.find( 387 if lowercasedPassword.find(
381 fwd, index + self.mirroredSequences["length"]) != -1: 388 fwd, index + self.mirroredSequences["length"]) != -1:
382 self.mirroredSequences["count"] += 1 389 self.mirroredSequences["count"] += 1
383 390
384 # Initial score based on length 391 # Initial score based on length
385 self.score["count"] = self.passwordLength["count"] * self.passwordLength["factor"] 392 self.score["count"] = self.passwordLength["count"] * \
393 self.passwordLength["factor"]
386 394
387 # passwordLength 395 # passwordLength
388 # credit additional length or punish "under" length 396 # credit additional length or punish "under" length
389 if self.passwordLength["count"] >= self.passwordLength["minimum"]: 397 if self.passwordLength["count"] >= self.passwordLength["minimum"]:
390 # credit additional characters over minimum 398 # credit additional characters over minimum
391 self.passwordLength["rating"] = self.passwordLength["bonus"] + \ 399 self.passwordLength["rating"] = self.passwordLength["bonus"] + \
392 (self.passwordLength["count"] - self.passwordLength["minimum"]) * \ 400 (self.passwordLength["count"] -
401 self.passwordLength["minimum"]) * \
393 self.passwordLength["factor"] 402 self.passwordLength["factor"]
394 else: 403 else:
395 self.passwordLength["rating"] = self.passwordLength["penalty"] 404 self.passwordLength["rating"] = self.passwordLength["penalty"]
396 self.score["count"] += self.passwordLength["rating"] 405 self.score["count"] += self.passwordLength["rating"]
397 406
398 # recommendedPasswordLength 407 # recommendedPasswordLength
399 # Credit reaching the recommended password length or put a 408 # Credit reaching the recommended password length or put a
400 # penalty on it 409 # penalty on it
401 if self.passwordLength["count"] >= self.recommendedPasswordLength["minimum"]: 410 if self.passwordLength["count"] >= \
411 self.recommendedPasswordLength["minimum"]:
402 self.recommendedPasswordLength["rating"] = \ 412 self.recommendedPasswordLength["rating"] = \
403 self.recommendedPasswordLength["bonus"] + \ 413 self.recommendedPasswordLength["bonus"] + \
404 (self.passwordLength["count"] - \ 414 (self.passwordLength["count"] - \
405 self.recommendedPasswordLength["minimum"]) * \ 415 self.recommendedPasswordLength["minimum"]) * \
406 self.recommendedPasswordLength["factor"] 416 self.recommendedPasswordLength["factor"]
410 self.score["count"] += self.recommendedPasswordLength["rating"] 420 self.score["count"] += self.recommendedPasswordLength["rating"]
411 421
412 # lowercaseLetters 422 # lowercaseLetters
413 # Honor or punish the lowercase letter use 423 # Honor or punish the lowercase letter use
414 if self.lowercaseLetters["count"] > 0: 424 if self.lowercaseLetters["count"] > 0:
415 self.lowercaseLetters["rating"] = self.lowercaseLetters["bonus"] + \ 425 self.lowercaseLetters["rating"] = \
416 self.lowercaseLetters["count"] * self.lowercaseLetters["factor"] 426 self.lowercaseLetters["bonus"] + \
427 self.lowercaseLetters["count"] * \
428 self.lowercaseLetters["factor"]
417 else: 429 else:
418 self.lowercaseLetters["rating"] = self.lowercaseLetters["penalty"] 430 self.lowercaseLetters["rating"] = self.lowercaseLetters["penalty"]
419 self.score["count"] += self.lowercaseLetters["rating"] 431 self.score["count"] += self.lowercaseLetters["rating"]
420 432
421 # uppercaseLetters 433 # uppercaseLetters
422 # Honor or punish the lowercase letter use 434 # Honor or punish the lowercase letter use
423 if self.uppercaseLetters["count"] > 0: 435 if self.uppercaseLetters["count"] > 0:
424 self.uppercaseLetters["rating"] = self.uppercaseLetters["bonus"] + \ 436 self.uppercaseLetters["rating"] = \
425 self.uppercaseLetters["count"] * self.uppercaseLetters["factor"] 437 self.uppercaseLetters["bonus"] + \
438 self.uppercaseLetters["count"] * \
439 self.uppercaseLetters["factor"]
426 else: 440 else:
427 self.uppercaseLetters["rating"] = self.uppercaseLetters["penalty"] 441 self.uppercaseLetters["rating"] = self.uppercaseLetters["penalty"]
428 self.score["count"] += self.uppercaseLetters["rating"] 442 self.score["count"] += self.uppercaseLetters["rating"]
429 443
430 # numerics 444 # numerics
464 self.score["count"] += self.middleNumerics["rating"] 478 self.score["count"] += self.middleNumerics["rating"]
465 479
466 # sequentialLetters 480 # sequentialLetters
467 # Honor or punish the sequential letter use 481 # Honor or punish the sequential letter use
468 if self.sequentialLetters["count"] == 0: 482 if self.sequentialLetters["count"] == 0:
469 self.sequentialLetters["rating"] = self.sequentialLetters["bonus"] + \ 483 self.sequentialLetters["rating"] = \
470 self.sequentialLetters["count"] * self.sequentialLetters["factor"] 484 self.sequentialLetters["bonus"] + \
471 else: 485 self.sequentialLetters["count"] * \
472 self.sequentialLetters["rating"] = self.sequentialLetters["penalty"] 486 self.sequentialLetters["factor"]
487 else:
488 self.sequentialLetters["rating"] = \
489 self.sequentialLetters["penalty"]
473 self.score["count"] += self.sequentialLetters["rating"] 490 self.score["count"] += self.sequentialLetters["rating"]
474 491
475 # sequentialNumerics 492 # sequentialNumerics
476 # Honor or punish the sequential numerics use 493 # Honor or punish the sequential numerics use
477 if self.sequentialNumerics["count"] == 0: 494 if self.sequentialNumerics["count"] == 0:
478 self.sequentialNumerics["rating"] = self.sequentialNumerics["bonus"] + \ 495 self.sequentialNumerics["rating"] = \
479 self.sequentialNumerics["count"] * self.sequentialNumerics["factor"] 496 self.sequentialNumerics["bonus"] + \
480 else: 497 self.sequentialNumerics["count"] * \
481 self.sequentialNumerics["rating"] = self.sequentialNumerics["penalty"] 498 self.sequentialNumerics["factor"]
499 else:
500 self.sequentialNumerics["rating"] = \
501 self.sequentialNumerics["penalty"]
482 self.score["count"] += self.sequentialNumerics["rating"] 502 self.score["count"] += self.sequentialNumerics["rating"]
483 503
484 # keyboardPatterns 504 # keyboardPatterns
485 # Honor or punish the keyboard patterns use 505 # Honor or punish the keyboard patterns use
486 if self.keyboardPatterns["count"] == 0: 506 if self.keyboardPatterns["count"] == 0:
487 self.keyboardPatterns["rating"] = self.keyboardPatterns["bonus"] + \ 507 self.keyboardPatterns["rating"] = \
488 self.keyboardPatterns["count"] * self.keyboardPatterns["factor"] 508 self.keyboardPatterns["bonus"] + \
509 self.keyboardPatterns["count"] * \
510 self.keyboardPatterns["factor"]
489 else: 511 else:
490 self.keyboardPatterns["rating"] = self.keyboardPatterns["penalty"] 512 self.keyboardPatterns["rating"] = self.keyboardPatterns["penalty"]
491 self.score["count"] += self.keyboardPatterns["rating"] 513 self.score["count"] += self.keyboardPatterns["rating"]
492 514
493 # Count our basicRequirements and set the status 515 # Count our basicRequirements and set the status
528 # requirement met 550 # requirement met
529 self.basicRequirements["count"] += 1 551 self.basicRequirements["count"] += 1
530 552
531 # judge the requirement status 553 # judge the requirement status
532 self.basicRequirements["status"] = self.__determineStatus( 554 self.basicRequirements["status"] = self.__determineStatus(
533 self.basicRequirements["count"] - self.basicRequirements["minimum"]) 555 self.basicRequirements["count"] -
556 self.basicRequirements["minimum"])
534 if self.basicRequirements["status"] != self.Status_Failed: 557 if self.basicRequirements["status"] != self.Status_Failed:
535 self.basicRequirements["rating"] = \ 558 self.basicRequirements["rating"] = \
536 self.basicRequirements["bonus"] + \ 559 self.basicRequirements["bonus"] + \
537 self.basicRequirements["factor"] * self.basicRequirements["count"] 560 self.basicRequirements["factor"] * \
538 else: 561 self.basicRequirements["count"]
539 self.basicRequirements["rating"] = self.basicRequirements["penalty"] 562 else:
563 self.basicRequirements["rating"] = \
564 self.basicRequirements["penalty"]
540 self.score["count"] += self.basicRequirements["rating"] 565 self.score["count"] += self.basicRequirements["rating"]
541 566
542 # beyond basic requirements 567 # beyond basic requirements
543 self.recommendedPasswordLength["status"] = self.__determineStatus( 568 self.recommendedPasswordLength["status"] = self.__determineStatus(
544 self.recommendedPasswordLength["count"] - \ 569 self.recommendedPasswordLength["count"] - \
563 # we apply them only, if the length is not awesome 588 # we apply them only, if the length is not awesome
564 if self.recommendedPasswordLength["status"] != self.Status_Exceeded: 589 if self.recommendedPasswordLength["status"] != self.Status_Exceeded:
565 # repeatedSequences 590 # repeatedSequences
566 # Honor or punish the use of repeated sequences 591 # Honor or punish the use of repeated sequences
567 if self.repeatedSequences["count"] == 0: 592 if self.repeatedSequences["count"] == 0:
568 self.repeatedSequences["rating"] = self.repeatedSequences["bonus"] 593 self.repeatedSequences["rating"] = \
594 self.repeatedSequences["bonus"]
569 else: 595 else:
570 self.repeatedSequences["rating"] = self.repeatedSequences["penalty"] + \ 596 self.repeatedSequences["rating"] = \
597 self.repeatedSequences["penalty"] + \
571 self.repeatedSequences["count"] * \ 598 self.repeatedSequences["count"] * \
572 self.repeatedSequences["factor"] 599 self.repeatedSequences["factor"]
573 600
574 # mirroredSequences 601 # mirroredSequences
575 # Honor or punish the use of mirrored sequences 602 # Honor or punish the use of mirrored sequences
576 if self.mirroredSequences["count"] == 0: 603 if self.mirroredSequences["count"] == 0:
577 self.mirroredSequences["rating"] = self.mirroredSequences["bonus"] 604 self.mirroredSequences["rating"] = \
605 self.mirroredSequences["bonus"]
578 else: 606 else:
579 self.mirroredSequences["rating"] = self.mirroredSequences["penalty"] + \ 607 self.mirroredSequences["rating"] = \
608 self.mirroredSequences["penalty"] + \
580 self.mirroredSequences["count"] * \ 609 self.mirroredSequences["count"] * \
581 self.mirroredSequences["factor"] 610 self.mirroredSequences["factor"]
582 611
583 # save value before redundancy 612 # save value before redundancy
584 self.score["beforeRedundancy"] = self.score["count"] 613 self.score["beforeRedundancy"] = self.score["count"]
585 614
586 # apply the redundancy 615 # apply the redundancy
587 # is the password length requirement fulfilled? 616 # is the password length requirement fulfilled?
588 if self.recommendedPasswordLength["status"] != self.Status_Exceeded: 617 if self.recommendedPasswordLength["status"] != self.Status_Exceeded:
589 # full penalty, because password is not long enough, only for a positive score 618 # full penalty, because password is not long enough, only for
619 # a positive score
590 if self.score["count"] > 0: 620 if self.score["count"] > 0:
591 self.score["count"] *= 1.0 / self.redundancy["value"] 621 self.score["count"] *= 1.0 / self.redundancy["value"]
592 622
593 # level it out 623 # level it out
594 if self.score["count"] > 100: 624 if self.score["count"] > 100:

eric ide

mercurial