passgen.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/usr/bin/env python
  2. #
  3. # Handy dandy library on how to do simple crypto in Python.
  4. #
  5. # Copyright 2017 kzimmermann <https://quitter.se/kzimmermann>
  6. #
  7. # This program is Free Software licensed under the terms and conditions of
  8. # the GNU GPL v3. See https://gnu.org/licenses
  9. #
  10. '''
  11. Portable "password-generation library" in python to generate strong or
  12. reusable passwords.
  13. Can be used as a module or as a standalone command-line program as long as
  14. getpass() is available.
  15. '''
  16. import hashlib
  17. import os
  18. import sys
  19. import binascii
  20. import base64 as b64
  21. from getpass import getpass
  22. def helper():
  23. print'''
  24. Strong password generator in python.
  25. Warning: prints password plaintext to stdout!
  26. USAGE: passgen.py [OPTION], where:
  27. -h, --help: prints this help message
  28. -r, --random: prints out a random password
  29. -k, --key: stretches the password into a key instead (only nonrandom)
  30. -l [length], --length [length]: prints out a password of [length]-chars
  31. '''
  32. def generate(salt, string, length=32):
  33. '''
  34. Generate a strong, yet deterministic password by making use of a common
  35. "salt" as a password seed and a service-specific string.
  36. Passwords are by default 32-char long, but should not be issued to less
  37. than 14 characters (80 bits entropy) due to the ease of brute-forcing.
  38. '''
  39. return b64.b64encode(hashlib.sha224(salt + string).hexdigest())[0:length]
  40. def passgen(length = 32, is_key = False):
  41. '''
  42. Practical application of the password generator functions.
  43. '''
  44. salt = getpass("Enter a salt: ")
  45. string = raw_input("Enter a service-specific string: ")
  46. if is_key:
  47. print "Your password is: %s" % keygen(salt, string, length)
  48. else:
  49. print "Your password is: %s" % generate(salt, string, length)
  50. def randpass(bits = 24):
  51. '''
  52. Returns a string composed of random bytes represented as a string, which
  53. is suitable for use as a password (though it does nothing to store it).
  54. Default is 24, which produces a 32-char string. You shouldn't use less
  55. than 9 bits, though.
  56. '''
  57. return binascii.b2a_hqx(os.urandom(bits))
  58. def keygen(string, salt, length = 32):
  59. '''
  60. Generates a strong, virtually unguessable key for a password by using
  61. a key stretching algorithm (PBKDF2) with a random salt. The type is str.
  62. By default, 24bits of salt are used.
  63. '''
  64. return binascii.b2a_hqx(
  65. hashlib.pbkdf2_hmac('sha256', string, salt, 200000)
  66. )[0:length]
  67. if __name__ == "__main__":
  68. def shift():
  69. "Practical implementation of the Unix shift command"
  70. sys.argv.reverse()
  71. sys.argv.pop()
  72. sys.argv.reverse()
  73. is_random = False
  74. is_key = False
  75. bits = 24
  76. length = 32
  77. shift()
  78. while len(sys.argv) > 0:
  79. arg = sys.argv[0]
  80. if arg == "-r" or arg == "--random":
  81. is_random = True
  82. elif arg == "-k" or arg == "--key":
  83. is_key = True
  84. elif arg == "-l" or arg == "--length":
  85. shift()
  86. try:
  87. if is_random:
  88. bits = int(sys.argv[0])
  89. else:
  90. length = int(sys.argv[0])
  91. except IndexError:
  92. print "Error: please specify a length"
  93. sys.exit(1)
  94. elif arg == "-h" or arg == "--help":
  95. helper()
  96. sys.exit(0)
  97. else:
  98. print "Error: unknown option '%s'" % arg
  99. sys.exit(1)
  100. # call next round...
  101. shift()
  102. if is_random:
  103. print randpass(bits)
  104. sys.exit(0)
  105. passgen(length, is_key)