Advertisement
Guest User

hash_generator

a guest
Mar 18th, 2024
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.53 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. """
  4. Translate a file of cleartext strings (passwords) to hashes.
  5.    NOTE: The field separator may be in the cleartext password
  6.    NOTE: Non-printable characters are retained in the output
  7.    NOTE: Strings not valid in UTF-8 are skipped
  8. """
  9.  
  10. ######################
  11. #  IMPORT LIBRARIES  #
  12. ######################
  13. import argparse
  14. from argparse import RawDescriptionHelpFormatter
  15. import fileinput
  16. import hashlib
  17. import os
  18. import sys
  19.  
  20.  
  21. ######################
  22. ## DEFINE FUNCTIONS ##
  23. ######################
  24. def argument_parser() -> argparse.Namespace:
  25.     """
  26.    Parse shell arguments
  27.    Help return is:
  28.    -----------------
  29.    usage: hash_generator.py [-h] [-s SEPARATOR] [-n] [-i [FILE]] [-o OUTPUT_FILE] [-e ERROR_FILE] [-a HASH_ALGORITHMS]
  30.           [-l | -u] [-v | -q]
  31.  
  32.    Translate a file of cleartext strings (passwords) to hashes
  33.        NOTE: The field separator may be in the cleartext
  34.        NOTE: Non-printable characters are retained in the output
  35.        NOTE: strings not valid in UTF-8 are skipped (see -e,-v,-q switches)
  36.  
  37.    options:
  38.    -h, --help            show this help message and exit
  39.    -s SEPARATOR, --separator SEPARATOR
  40.                            The column separator to use in the output file if specified (default ':')
  41.    -n, --no-header       Do not print the header line
  42.  
  43.    File Management:
  44.    -i [FILE], --input-file [FILE]
  45.                            The input file of strings to parse, if omitted STDIN is used
  46.    -o OUTPUT_FILE, --output-file OUTPUT_FILE
  47.                            Output file, if omitted STDOUT is used
  48.    -e ERROR_FILE, --error-file ERROR_FILE
  49.                            Optional file to write lines that cannot be parsed
  50.  
  51.    Hash:
  52.    -a HASH_ALGORITHMS, --hash-algorithms HASH_ALGORITHMS
  53.                            Comma separated Hash list to use (default: sha1) options are:
  54.                            sha1, sha224, sha256, sha384, sha512,
  55.                            sha3_224, sha3_256, sha3_384, sha3_512,
  56.                            blake2b, blake2s, md5
  57.    -l, --hash-lower      Output the hash value in lowercase (default)
  58.    -u, --hash-upper      Output the hash value in UPPERCASE
  59.  
  60.    Output Verbosity:
  61.    -v, --verbose         Verbose reporting of warnings (skipped lines) to STDERR (see -e switch)
  62.    -q, --quiet           Suppress all console output (STDOUT/STDERR)
  63.    -----------------
  64.    """
  65.     # Create argparse instance
  66.     arg_parser = argparse.ArgumentParser(
  67.         formatter_class = RawDescriptionHelpFormatter,
  68.         description = "Translate a file of cleartext strings (passwords) to hashes\n"\
  69.                       "    NOTE: The field separator may be in the cleartext\n"\
  70.                       "    NOTE: Non-printable characters are retained in the output\n"\
  71.                       "    NOTE: strings not valid in UTF-8 are skipped (see -e,-v,-q switches)")
  72.     # General Arguments
  73.     arg_parser.add_argument('-s','--separator',
  74.                                 default = ':',
  75.                                 help = "The column separator to use in the output file if specified (default ':')")
  76.     arg_parser.add_argument('-n','--no-header',
  77.                                 action = 'store_true',
  78.                                 default = False,
  79.                                 help = "Do not print the header line")
  80.     # File Arguments
  81.     argument_group_files = arg_parser.add_argument_group('File Management')
  82.     argument_group_files.add_argument('-i', '--input-file',
  83.                                     metavar = 'FILE',
  84.                                     nargs = '?',
  85.                                     default = [],
  86.                                     help = "The input file of strings to parse, if omitted STDIN is used")
  87.     argument_group_files.add_argument('-o', '--output-file',
  88.                                     help = "Output file, if omitted STDOUT is used")
  89.     argument_group_files.add_argument('-e', '--error-file',
  90.                                     help = "Optional file to write lines that cannot be parsed")
  91.     # Hash formatting
  92.     argument_group_hash_wrapper = arg_parser.add_argument_group('Hash')
  93.     argument_group_hash_wrapper.add_argument('-a', '--hash-algorithms',
  94.                                     default = 'sha1',
  95.                                     help = 'Comma separated Hash list to use (default: sha1) options are: '\
  96.                                            'sha1, sha224, sha256, sha384, sha512, '\
  97.                                            'sha3_224, sha3_256, sha3_384, sha3_512, '\
  98.                                            'blake2b, blake2s, md5')
  99.     argument_group_hash = argument_group_hash_wrapper.add_mutually_exclusive_group()
  100.     argument_group_hash.add_argument('-l', '--hash-lower',
  101.                                     action='store_true',
  102.                                     help='Output the hash value in lowercase (default)')
  103.     argument_group_hash.add_argument('-u', '--hash-upper',
  104.                                     action='store_true',
  105.                                     help='Output the hash value in UPPERCASE')
  106.     # Console output
  107.     argument_group_verbosity_parent =  arg_parser.add_argument_group('Output Verbosity')
  108.     argument_group_verbosity = argument_group_verbosity_parent.add_mutually_exclusive_group()
  109.     argument_group_verbosity.add_argument('-v', '--verbose',
  110.                                         action='store_true',
  111.                                         help="Verbose reporting of warnings (skipped lines) to STDERR (see -e switch)")
  112.     argument_group_verbosity.add_argument('-q', '--quiet',
  113.                                         action='store_true',
  114.                                         help="Suppress all console output (STDOUT/STDERR)")
  115.     script_arguments= arg_parser.parse_args()
  116.     return script_arguments
  117.  
  118. def hash_string(text_string: str, hash_type: str = "sha1", hash_uppercase: bool = True) -> str:
  119.     """
  120.    Returns a hex hash based on the hash_type and text_string provided
  121.    """
  122.     match hash_type:
  123.         case "sha1":
  124.             return_value = hashlib.sha1(text_string.encode()).hexdigest()
  125.         case "sha224":
  126.             return_value = hashlib.sha224(text_string.encode()).hexdigest()
  127.         case "sha256":
  128.             return_value = hashlib.sha256(text_string.encode()).hexdigest()
  129.         case "sha384":
  130.             return_value = hashlib.sha384(text_string.encode()).hexdigest()
  131.         case "sha512":
  132.             return_value = hashlib.sha512(text_string.encode()).hexdigest()
  133.         case "sha3_224":
  134.             return_value = hashlib.sha3_224(text_string.encode()).hexdigest()
  135.         case "sha3_256":
  136.             return_value = hashlib.sha3_256(text_string.encode()).hexdigest()
  137.         case "sha3_384":
  138.             return_value = hashlib.sha3_384(text_string.encode()).hexdigest()
  139.         case "sha3_512":
  140.             return_value = hashlib.sha3_512(text_string.encode()).hexdigest()
  141.         # Shake requires an unknown length argument
  142.         #case "shake_128":
  143.         #    return_value = hashlib.shake_128(text_string.encode()).hexdigest()
  144.         #case "shake_256":
  145.         #    return_value = hashlib.shake_256(text_string.encode()).hexdigest()
  146.         case "blake2b":
  147.             return_value = hashlib.blake2b(text_string.encode()).hexdigest()
  148.         case "blake2s":
  149.             return_value = hashlib.blake2s(text_string.encode()).hexdigest()
  150.         case "md5":
  151.             return_value = hashlib.md5(text_string.encode()).hexdigest()
  152.         case _:
  153.             print(f"hash type: {hash_type}, not supported, exiting.")
  154.             exit(-1)
  155.     if hash_uppercase:
  156.         return return_value.upper()
  157.     else:
  158.         return return_value
  159.  
  160. def main() -> int:
  161.     """
  162.    Main entry point.
  163.    """
  164.     # Initialize variables
  165.     counter_warnings = 0
  166.     counter_errors   = 0
  167.     counter_success  = 0
  168.     supported_hashes = [
  169.         "sha1", "sha224", "sha256", "sha284", "sha512", #SHA
  170.         "sha3_224", "sha3_384", "sha3_512", # SHA3
  171.         "blake2b", "blake2s", "md5" # Misc
  172.     ]
  173.  
  174.     # Parse arguments
  175.     script_arguments = argument_parser()
  176.  
  177.     # Verify hash list includes only supported hashes
  178.     hash_list = str(script_arguments.hash_algorithms).lower().split(",")
  179.     hash_list[:] = [entry.strip() for entry in hash_list] # strip spaces from entries
  180.     for hash_name in hash_list:
  181.         if hash_name not in supported_hashes:
  182.             print(f"hash type: {hash_name}, not supported, exiting.")
  183.             exit(-1)
  184.     if script_arguments.verbose:
  185.         if script_arguments.output_file:
  186.             print(f"The following hashes were selected: {hash_list}")
  187.         else:
  188.             print(f"The following hashes were selected: {hash_list}", file=sys.stderr)
  189.  
  190.     # Open files if specified
  191.     if script_arguments.output_file:
  192.         try:
  193.             file_output = open(file=script_arguments.output_file, mode='w', encoding="utf-8")
  194.         except IOError as err:
  195.             print(f"ERROR: unable to open file '{script_arguments.output_file}' for writing", file=sys.stderr)
  196.             print("    Details: ", end='', file=sys.stderr)
  197.             print(Exception, err, file=sys.stderr)
  198.             sys.exit(0)
  199.     if script_arguments.error_file:
  200.         try:
  201.             file_error = open(file=script_arguments.error_file, mode='w', encoding="utf-8")
  202.         except IOError as err:
  203.             print(f"ERROR: unable to open file '{script_arguments.error_file}' for writing errors", file=sys.stderr)
  204.             print("    Details: ", end='', file=sys.stderr)
  205.             print(Exception, err, file=sys.stderr)
  206.             sys.exit(0)
  207.  
  208.     # Print header line
  209.     if script_arguments.no_header is not True:
  210.         if script_arguments.output_file:
  211.             print(*hash_list, "clear", sep=script_arguments.separator, file=file_output)
  212.         else:
  213.             print(*hash_list, "clear", sep=script_arguments.separator)
  214.  
  215.     # Process input file or STDIN
  216.     for input_line in fileinput.input(files=script_arguments.input_file):
  217.         try:
  218.             result_line=""
  219.             for hash_name in hash_list:
  220.                 if script_arguments.hash_upper:
  221.                     result_line += hash_string(input_line[0:-1], hash_name, True) + script_arguments.separator
  222.                 else:
  223.                     result_line += hash_string(input_line[0:-1], hash_name, False) + script_arguments.separator
  224.             result_line += input_line[0:-1]
  225.  
  226.             if script_arguments.output_file:
  227.                 print(result_line, file=file_output)
  228.             else:
  229.                 print(result_line)
  230.             counter_success += 1
  231.         except IOError as err:
  232.             if script_arguments.verbose:
  233.                 print(f"ERROR: line #{str(fileinput.lineno())} skipped: {input_line[0:-1]}", file=sys.stderr)
  234.                 print("    Details: ", end='', file=sys.stderr)
  235.                 print(Exception, err, file=sys.stderr)
  236.             if script_arguments.error_file:
  237.                 file_error.write(input_line)
  238.             counter_errors += 1
  239.  
  240.     if script_arguments.quiet is not True:
  241.         if script_arguments.output_file:
  242.             if counter_success:
  243.                 print(f"{str(fileinput.lineno()).rjust(12)} lines processed from: {fileinput.filename()}")
  244.                 print(f"{str(counter_success).rjust(12)} lines written to: {file_output.name}.")
  245.             if script_arguments.error_file:
  246.                 if (counter_warnings + counter_errors) > 0:
  247.                     print(f"{str(counter_warnings + counter_errors).rjust(12)} errored lines written to: "\
  248.                         f"{file_error.name}.")
  249.             else:
  250.                 if counter_errors > 0:
  251.                     print(f"Errors identified: {str(counter_errors)}", file=sys.stderr)
  252.                 if counter_warnings > 0:
  253.                     print(f"Warnings detected: {counter_warnings} (use -v / --verbose for details)", file=sys.stderr)
  254.  
  255.     # Cleanup and exit
  256.     fileinput.close()
  257.     if script_arguments.output_file:
  258.         file_output.close()
  259.         if os.path.getsize(script_arguments.output_file) == 0:
  260.             os.remove(script_arguments.output_file)
  261.             print(f"No output to file ({script_arguments.output_file}), file deleted.")
  262.     if script_arguments.error_file:
  263.         file_error.close()
  264.         if os.path.getsize(script_arguments.error_file) == 0:
  265.             os.remove(script_arguments.error_file)
  266.     return
  267.  
  268. #####################
  269. #  BEGIN PROCESSING #
  270. #####################
  271. if __name__ == '__main__':
  272.     sys.exit(main())
  273.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement