123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- #!/usr/bin/env python
- #
- # Handy dandy library on how to do simple crypto in Python.
- #
- # Copyright 2017 kzimmermann <https://quitter.se/kzimmermann>
- #
- # This program is Free Software licensed under the terms and conditions of
- # the GNU GPL v3. See https://gnu.org/licenses
- #
- '''
- Portable "password-generation library" in python to generate strong or
- reusable passwords.
- Can be used as a module or as a standalone command-line program as long as
- getpass() is available.
- '''
- import hashlib
- import os
- import sys
- import binascii
- import base64 as b64
- from getpass import getpass
- def helper():
- print'''
- Strong password generator in python.
- Warning: prints password plaintext to stdout!
- USAGE: passgen.py [OPTION], where:
- -h, --help: prints this help message
- -r, --random: prints out a random password
- -k, --key: stretches the password into a key instead (only nonrandom)
- -l [length], --length [length]: prints out a password of [length]-chars
- '''
- def generate(salt, string, length=32):
- '''
- Generate a strong, yet deterministic password by making use of a common
- "salt" as a password seed and a service-specific string.
- Passwords are by default 32-char long, but should not be issued to less
- than 14 characters (80 bits entropy) due to the ease of brute-forcing.
- '''
- return b64.b64encode(hashlib.sha224(salt + string).hexdigest())[0:length]
- def passgen(length = 32, is_key = False):
- '''
- Practical application of the password generator functions.
- '''
- salt = getpass("Enter a salt: ")
- string = raw_input("Enter a service-specific string: ")
- if is_key:
- print "Your password is: %s" % keygen(salt, string, length)
- else:
- print "Your password is: %s" % generate(salt, string, length)
- def randpass(bits = 24):
- '''
- Returns a string composed of random bytes represented as a string, which
- is suitable for use as a password (though it does nothing to store it).
- Default is 24, which produces a 32-char string. You shouldn't use less
- than 9 bits, though.
- '''
- return binascii.b2a_hqx(os.urandom(bits))
- def keygen(string, salt, length = 32):
- '''
- Generates a strong, virtually unguessable key for a password by using
- a key stretching algorithm (PBKDF2) with a random salt. The type is str.
- By default, 24bits of salt are used.
- '''
- return binascii.b2a_hqx(
- hashlib.pbkdf2_hmac('sha256', string, salt, 200000)
- )[0:length]
- if __name__ == "__main__":
- def shift():
- "Practical implementation of the Unix shift command"
- sys.argv.reverse()
- sys.argv.pop()
- sys.argv.reverse()
- is_random = False
- is_key = False
- bits = 24
- length = 32
- shift()
- while len(sys.argv) > 0:
- arg = sys.argv[0]
- if arg == "-r" or arg == "--random":
- is_random = True
- elif arg == "-k" or arg == "--key":
- is_key = True
- elif arg == "-l" or arg == "--length":
- shift()
- try:
- if is_random:
- bits = int(sys.argv[0])
- else:
- length = int(sys.argv[0])
- except IndexError:
- print "Error: please specify a length"
- sys.exit(1)
- elif arg == "-h" or arg == "--help":
- helper()
- sys.exit(0)
- else:
- print "Error: unknown option '%s'" % arg
- sys.exit(1)
- # call next round...
- shift()
-
- if is_random:
- print randpass(bits)
- sys.exit(0)
- passgen(length, is_key)
|