1#!/usr/bin/env python 2# 3# Copyright (c) ZeroC, Inc. All rights reserved. 4# 5 6import sys, getopt, passlib.hash, passlib.hosts, getpass 7 8usePBKDF2 = any(sys.platform == p for p in ["win32", "darwin", "cygwin"]) 9useCryptExt = any(sys.platform.startswith(p) for p in ["linux", "freebsd", "gnukfreebsd"]) 10 11def usage(): 12 print("Usage: icehashpassword [options]") 13 print("") 14 print("OPTIONS") 15 16 if usePBKDF2: 17 print("") 18 print(" -d MESSAGE_DIGEST_ALGORITHM, --digest=MESSAGE_DIGEST_ALGORITHM") 19 print(" The message digest algorithm to use with PBKDF2, valid values are (sha1, sha256, sha512).") 20 print("") 21 print(" -s SALT_SIZE, --salt=SALT_SIZE") 22 print(" Optional number of bytes to use when generating new salts.") 23 print("") 24 elif useCryptExt: 25 print(" -d MESSAGE_DIGEST_ALGORITHM, --digest=MESSAGE_DIGEST_ALGORITHM") 26 print(" The message digest algorithm to use with crypt function, valid values are (sha256, sha512).") 27 print("") 28 if usePBKDF2 or useCryptExt: 29 print(" -r ROUNDS, --rounds=ROUNDS") 30 print(" Optional number of rounds to use.") 31 print("") 32 print(" -h, --help" ) 33 print(" Show this message.") 34 print("") 35 36def main(): 37 38 digestAlgorithms = () 39 shortArgs = "h" 40 longArgs = ["help"] 41 if usePBKDF2: 42 shortArgs += "d:s:r:" 43 longArgs += ["digest=", "salt=", "rounds="] 44 digestAlgorithms = ("sha1", "sha256", "sha512") 45 elif useCryptExt: 46 shortArgs += "d:r:" 47 longArgs += ["digest=", "rounds="] 48 digestAlgorithms = ("sha256", "sha512") 49 50 try: 51 opts, args = getopt.getopt(sys.argv[1:], shortArgs, longArgs) 52 except getopt.GetoptError as err: 53 print("") 54 print(str(err)) 55 usage() 56 return 2 57 58 digest = None 59 salt = None 60 rounds = None 61 62 for o, a in opts: 63 if o in ("-h", "--help"): 64 usage() 65 return 0 66 elif o in ("-d", "--digest"): 67 if a in digestAlgorithms: 68 digest = a 69 else: 70 print("Unknown digest algorithm `" + a + "'") 71 return 2 72 elif o in ("-s", "--salt"): 73 try: 74 salt = int(a) 75 except ValueError as err: 76 print("Invalid salt size. Value must be an integer") 77 usage() 78 return 2 79 elif o in ("-r", "--rounds"): 80 try: 81 rounds = int(a) 82 except ValueError as err: 83 print("Invalid number of rounds. Value must be an integer") 84 usage() 85 return 2 86 87 passScheme = None 88 if usePBKDF2: 89 passScheme = passlib.hash.pbkdf2_sha256 90 if digest == "sha1": 91 passScheme = passlib.hash.pbkdf2_sha1 92 elif digest == "sha512": 93 passScheme = passlib.hash.pbkdf2_sha512 94 elif useCryptExt: 95 passScheme = passlib.hash.sha512_crypt 96 if digest == "sha256": 97 passScheme = passlib.hash.sha256_crypt 98 else: 99 # 100 # Fallback is the OS crypt function 101 # 102 passScheme = passlib.hosts.host_context 103 104 if rounds: 105 if not passScheme.min_rounds <= rounds <= passScheme.max_rounds: 106 print("Invalid number rounds for the digest algorithm. Value must be an integer between %s and %s" % 107 (passScheme.min_rounds, passScheme.max_rounds)) 108 usage() 109 return 2 110 if salt: 111 if not passScheme.min_salt_size <= salt <= passScheme.max_salt_size: 112 print("Invalid salt size for the digest algorithm. Value must be an integer between %s and %s" % 113 (passScheme.min_salt_size, passScheme.max_salt_size)) 114 usage() 115 return 2 116 117 args = [] 118 if sys.stdout.isatty(): 119 args.append(getpass.getpass("Password: ")) 120 else: 121 args.append(sys.stdin.readline().strip()) 122 123 opts = {} 124 if salt: 125 opts["salt_size"] = salt 126 127 if rounds: 128 opts["rounds"] = rounds 129 130 # passlib 1.7 renamed encrypt to hash 131 if hasattr(passScheme, "hash"): 132 print(passScheme.using(**opts).hash(*args)) 133 else: 134 print(passScheme.encrypt(*args, **opts)) 135 136 return 0 137 138if __name__ == '__main__': 139 sys.exit(main()) 140