| #!/usr/bin/env python3 |
| # |
| # SPDX-FileCopyrightText: © 2020 Open Networking Foundation <support@opennetworking.org> |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| # goodpassword.py |
| |
| import getpass |
| import sys |
| import zxcvbn |
| from passlib.hash import bcrypt, sha512_crypt |
| |
| MIN_LEN = 12 |
| REQ_SCORE = 4 |
| |
| print("goodpassword.py - generates unix password hashes of high quality") |
| pw = getpass.getpass() |
| |
| # reject short passwords |
| pwlen = len(pw) |
| if pwlen < MIN_LEN: |
| print( |
| "Passwords must be at least %d characters long (the one supplied was %d)." |
| % (MIN_LEN, pwlen) |
| ) |
| sys.exit(1) |
| |
| # generate password score |
| zxscore = zxcvbn.zxcvbn(pw) |
| |
| # Print any suggestions |
| if zxscore["feedback"]["warning"]: |
| print("Warning: %s" % zxscore["feedback"]["warning"]) |
| |
| if zxscore["feedback"]["suggestions"]: |
| print("Suggestions:") |
| for suggestion in zxscore["feedback"]["suggestions"]: |
| print(" - %s" % suggestion) |
| |
| print( |
| "This password had a complexity score of %d (must score at least %d)" |
| % (zxscore["score"], REQ_SCORE) |
| ) |
| |
| print( |
| "Time to crack: %s" |
| % zxscore["crack_times_display"]["offline_slow_hashing_1e4_per_second"] |
| ) |
| |
| years = 5 |
| min_crack_seconds = 60 * 60 * 24 * 365 * years # number of seconds per year |
| # if the password crack time is too short |
| if ( |
| zxscore["crack_times_seconds"]["offline_slow_hashing_1e4_per_second"] |
| < min_crack_seconds |
| ): |
| print( |
| "This password was crackable in less than %d years, please make it longer/more complex" |
| % years |
| ) |
| sys.exit(1) |
| |
| # if the password score is too low |
| if zxscore["score"] < REQ_SCORE: |
| sys.exit(1) |
| |
| # password is high enough quality |
| # this make take a short while so let the user know |
| print("Generating password hashes...") |
| print('bcrypt: "%s"' % bcrypt.using(rounds=16).hash(pw)) |
| print('sha512crypt: "%s"' % sha512_crypt.hash(pw)) |