Created
August 4, 2013 16:36
-
-
Save x684867/6150915 to your computer and use it in GitHub Desktop.
tableBuilder.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| # | |
| # Universal Hash Table calculator | |
| # (c) 2013 Sam Caldwell. All Rights Reserved. | |
| # | |
| # ------------------------------------------------------------------------------ | |
| # *** LIMITED INTERNAL-USE LICENSE *** | |
| # Script intended and authorized solely for research and education purposes | |
| # to identify the weaknesses of current cryptographic practices in place on | |
| # many systems so that the system operators can appreciate the use of best | |
| # practices. Use of this script for illegal or harmful purposes is prohibited | |
| # and may result in criminal or civil penalties. The user is forewarned that | |
| # the author *will* cooperate with law enforcement in his jurisdiction in the | |
| # non-political prosecution of persons believed to have used this script or | |
| # derived work to harm any person or organization or to otherwise violate the | |
| # laws of the United States or any state thereof. | |
| # | |
| # Use of this script indicates an acknowledgement of and consent to these terms | |
| # and conditions and an agreement to indemnify and hold harmless the author in | |
| # any and all cases which may arise from your use hereof directly or indirectly. | |
| # ------------------------------------------------------------------------------ | |
| # Theory of operation: | |
| # | |
| # 1. Parse arguments (params array) | |
| # 2. Create the hashes table directory base_dir | |
| # 3. Calculate Hashes | |
| # a. create the starting keyspace={start_char,start_char...} of width elements. | |
| # b. hash keyspace | |
| # c. increment the keyspace by recursively incrementing each | |
| # element as the 1 is carried. | |
| # | |
| require 'optparse' | |
| require 'fileutils' | |
| require 'digest/md5' | |
| require 'digest/sha1' | |
| require 'digest/sha2' | |
| require 'logger' | |
| GC.enable | |
| GC.start | |
| def throw_missing_param() | |
| puts "Missing expected operand. Use -h or --help for USAGE information." | |
| abort | |
| end | |
| def throw_bad_keyspace() | |
| puts "stop_char must be greater than start_char" | |
| puts "This value must also be a valid decimal ASCII code." | |
| puts "Use -h or --help for more information." | |
| abort | |
| end | |
| def throw_bad_width() | |
| puts "width must be greater than zero (0)" | |
| puts "Use -h or --help for more information." | |
| abort | |
| end | |
| def show_usage() | |
| puts "------------------------------------------------------------------------------" | |
| puts " Universal Hash Table calculator" | |
| puts " (c) 2013 Sam Caldwell. All Rights Reserved." | |
| puts "------------------------------------------------------------------------------" | |
| puts "USAGE:" | |
| puts " tableBuilder.rb base_dir start_char stop_char width max_thread_count" | |
| puts " " | |
| puts " base_dir (string) : base directory path" | |
| puts " start_char (int) : starting ASCII character value" | |
| puts " stop_char (int) : ending ASCII character value" | |
| puts " key_width (int) : width of the keyspace to be analyzed" | |
| puts " max_thread_count(int) : maximum number of threads allowed" | |
| puts "------------------------------------------------------------------------------" | |
| puts "EXAMPLE:" | |
| puts " tableBuilder.rb ./hashes 32 127 16 1000" | |
| puts " " | |
| puts " This call would generate a table of hashes at ./hashes/... with a" | |
| puts " 1-16 character keyspace of characters ranging from ASCII 32 to" | |
| puts " ASCII 127 using MD5, SHA1, SHA256, SHA384 and SHA512 algorithms." | |
| puts " " | |
| puts " Each cleartext would be stored in a directory tree made up of its" | |
| puts " hexadecimal hash digits in a file named for the algorithm used, as" | |
| puts " follows:" | |
| puts " " | |
| puts " ./hashes/d/8/e/8/f/c/a/.../MD5.txt" | |
| puts " " | |
| puts " This means that given a hash, one can rewrite the hash as the" | |
| puts " hash and filename of the file where its cleartext counterpart" | |
| puts " is stored." | |
| puts " " | |
| puts " RELATED WORK:" | |
| puts " " | |
| puts " A subsequent project could be created down the road to create a" | |
| puts " clear-text to cipher-text cross-reference by symlinking to these" | |
| puts " hash tables. This would have little lookup power other than being" | |
| puts " able to identify and inventory the passwords compromised by this" | |
| puts " system." | |
| puts "------------------------------------------------------------------------------" | |
| exit | |
| end | |
| def show_welcome(baseDir,startChar,stopChar,width,max_thread_count) | |
| puts "-- -- -- -- -- -- -- -- -- -- -- -- -- --" | |
| puts "Starting..." | |
| puts " base_dir: " + baseDir | |
| puts " start_char: " + startChar.to_s + " (ASCII)" | |
| puts " stop_char: " + stopChar.to_s + " (ASCII)" | |
| puts " width: " + width.to_s + " chars" | |
| puts " max_thread_count: " + max_thread_count.to_s + " threads" | |
| puts "-- -- -- -- -- -- -- -- -- -- -- -- -- --" | |
| end | |
| def throw_insufficient_threads() | |
| puts "max_thread_count is too low." | |
| puts "use -h or --help for usage information." | |
| abort | |
| end | |
| def min_thread_count(stop_char,start_char) | |
| return (stop_char - start_char + 10) | |
| end | |
| def join_keyspace(keyspace) | |
| s="" | |
| #join they keyspace as characters. | |
| keyspace.each do |e| | |
| s=s+e.chr | |
| end | |
| return s | |
| end | |
| def hash2dir(base_dir,key_hash) | |
| #strip any trailing slash | |
| hash_dir=base_dir.chomp('/') | |
| #parse each char of the hash to create directory structure. | |
| key_hash.each_char do |n| | |
| hash_dir=hash_dir+"/"+n | |
| end | |
| #return hash-directory path without trailing / char. | |
| return hash_dir | |
| end | |
| def pretty_join(i) | |
| s="" | |
| i.each do | e | | |
| s=s+" "+e.to_s(16) unless(e == 0) | |
| end | |
| return s | |
| end | |
| def write_hash_file(base_dir,algorithm,key,hashstring) | |
| #stringify the keyspace array as a string of ASCII characters. | |
| key_string=pretty_join(key).to_s | |
| #Convert the hash into a directory path if it doesn't exist. | |
| #table_path=File.dirname(hash2dir(base_dir,hashstring.to_s)) | |
| #FileUtils.mkdir_p(table_path) if not File.directory?(table_path) | |
| # Store the cleartext key into a file named for the current algorithm | |
| # if no such file exists.... | |
| #cleartext_file=table_path+"/"+algorithm+".txt" | |
| cleartext_file=base_dir+"/md5.txt" | |
| #output_file=File.new(cleartext_file,'w') if not File.exists?(cleartext_file) | |
| output_file=File.new(cleartext_file,'a') | |
| if(output_file) | |
| output_file.puts(hashstring.to_s+" "+key_string) | |
| puts "wrote "+cleartext_file+" with cleartext string "+key_string | |
| output_file.close | |
| return true | |
| else | |
| puts "skipped existing hash file "+cleartext_file+" with cleartext string "+key_string | |
| return false | |
| end | |
| end | |
| def check_keyspace_end(keyspace,width,stop_char) | |
| check_flag=false | |
| width.times do |i| | |
| check_flag=true if(keyspace[i]==stop_char) | |
| end | |
| return check_flag | |
| end | |
| def increment_keyspace(keyspace,index,start_char,stop_char,width) | |
| if(index > width) | |
| return check_keyspace_end(keyspace,width,stop_char) | |
| else | |
| if(keyspace[index]>=stop_char) | |
| keyspace[index]=0 | |
| return increment_keyspace(keyspace,index+1,start_char,stop_char,width) | |
| else | |
| if((keyspace[index]==0) and (start_char>0)) | |
| keyspace[index]=start_char | |
| else | |
| keyspace[index]=keyspace[index]+1 | |
| end | |
| return false | |
| end | |
| end | |
| end | |
| def initialize_keyspace(slice,width) | |
| # | |
| # We are going to initialize each keyspace with | |
| # the 0-th element being the slice character value. | |
| # This means that we can multithread the application. | |
| # workload. | |
| # | |
| keyspace=Array.new(width) | |
| width.times do |i| | |
| keyspace[i]=0 | |
| end | |
| keyspace[0]=slice | |
| return keyspace | |
| end | |
| def calculateHashes(dir_name,keyspace,start_char,stop_char,width,max_thread_count,log) | |
| hash_count=0 | |
| write_count=0 | |
| is_complete=false | |
| child_threads=Array.new | |
| until is_complete do | |
| log.info "TC:"+Thread.list.count.to_s+" h="+hash_count.to_s+" w="+write_count.to_s+" ks="+keyspace.to_s | |
| throttle_thread_count(max_thread_count) | |
| if(Thread.list.count <= max_thread_count) | |
| child_threads[Thread.list.count]=Thread.new do | |
| if(write_hash_file( | |
| dir_name, | |
| "MD5", | |
| keyspace, | |
| Digest::MD5.hexdigest(join_keyspace(keyspace)) | |
| ) | |
| ) | |
| write_count=write_count+1 | |
| end | |
| hash_count=hash_count+1 | |
| end | |
| end | |
| #if(Thread.list.count <= max_thread_count) | |
| # child_threads[Thread.list.count]=Thread.new do | |
| # write_hash_file( | |
| # dir_name, | |
| # "SHA1", | |
| # keyspace, | |
| # Digest::SHA1.hexdigest(join_keyspace(keyspace)) | |
| # ) | |
| # end | |
| #end | |
| #if(Thread.list.count <= max_thread_count) | |
| #threads[Thread.list.count]=Thread.new do | |
| # write_hash_file( | |
| # dir_name, | |
| # "SHA256", | |
| # keyspace, | |
| # Digest::SHA256.hexdigest(join_keyspace(keyspace)) | |
| # ) | |
| #end | |
| #end | |
| #if(Thread.list.count <= max_thread_count) | |
| #threads[Thread.list.count]=Thread.new do | |
| # write_hash_file( | |
| # dir_name, | |
| # "SHA384", | |
| # keyspace, | |
| # Digest::SHA384.hexdigest(join_keyspace(keyspace)) | |
| # ) | |
| #end | |
| #end | |
| #if(Thread.list.count <= max_thread_count) | |
| #threads[Thread.list.count]=Thread.new do | |
| # write_hash_file( | |
| # dir_name, | |
| # "SHA512", | |
| # keyspace, | |
| # Digest::SHA512.hexdigest(join_keyspace(keyspace)) | |
| # ) | |
| #end | |
| #end | |
| is_complete=increment_keyspace(keyspace,0,start_char,stop_char,width) | |
| end | |
| puts "calculateHashes() done." | |
| end | |
| def throttle_thread_count(max_thread_count) | |
| while(Thread.list.count > max_thread_count) | |
| log.info "Cannot start any more threads...NEED MORE COWBELL! Sleeping 5 seconds." | |
| puts "Cannot start any more threads...NEED MORE COWBELL! Sleeping 5 seconds." | |
| sleep(5) | |
| end | |
| end | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| # MAIN ROUTINE | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| # SETUP SYSLOG... | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| log=Logger.new 'tableBuilder' | |
| log.info 'tableBuilder log initialized.' | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| # PARSE ARGUMENTS... | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| show_usage() if((ARGV[0]=="-h") || (ARGV[0]=="--help")) | |
| (base_dir=ARGV[0]) or throw_missing_param() | |
| (start_char=ARGV[1].to_i) or throw_missing_param() | |
| (stop_char=ARGV[2].to_i) or throw_missing_param() | |
| (width=ARGV[3].to_i) or throw_missing_param() | |
| (max_thread_count=ARGV[4].to_i) or throw_missing_param() | |
| show_welcome(base_dir,start_char,stop_char,width,max_thread_count) | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| # VALIDATE INPUTS... | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| throw_bad_keyspace() if(stop_char <= start_char) | |
| throw_bad_width() if(width<=0) | |
| throw_insufficient_threads() if(max_thread_count < min_thread_count(stop_char,start_char)) | |
| #-- -- -- -- -- -- -- -- -- -- -- -- -- -- | |
| puts "Initializing Keyspaces..." | |
| calculateHashes( | |
| base_dir, | |
| initialize_keyspace(0,width), | |
| start_char, | |
| stop_char, | |
| width, | |
| max_thread_count, | |
| log | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment