Cryptography

Generating Hashes

MD5 hash

  1. require 'digest'
  2. puts Digest::MD5.hexdigest 'P@ssw0rd'

SHA1 hash

  1. require 'digest'
  2. puts Digest::SHA1.hexdigest 'P@ssw0rd'

SHA2 hash

In SHA2 you have 2 ways to do it.

Way #1: By creating a new SHA2 hash object with a given bit length.

  1. require 'digest'
  2. # 1
  3. sha2_256 = Digest::SHA2.new(bitlen = 256) # bitlen could be 256, 384, 512
  4. sha2_256.hexdigest 'P@ssw0rd'
  5. # 2
  6. Digest::SHA2.new(bitlen = 256).hexdigest 'P@ssw0rd'

Way #2: By Using the class directly

  1. require 'digest'
  2. puts Digest::SHA256.hexdigest 'P@ssw0rd'
  3. puts Digest::SHA384.hexdigest 'P@ssw0rd'
  4. puts Digest::SHA512.hexdigest 'P@ssw0rd'

Bonus: Generate Linux-like Shadow password

  1. require 'digest/sha2'
  2. password = 'P@ssw0rd'
  3. salt = rand(36**8).to_s(36)
  4. shadow_hash = password.crypt("$6$" + salt)

Windows LM Password hash

  1. require 'openssl'
  2. def split7(str)
  3. str.scan(/.{1,7}/)
  4. end
  5. def gen_keys(str)
  6. split7(str).map do |str7|
  7. bits = split7(str7.unpack("B*")[0]).inject('') do |ret, tkn|
  8. ret += tkn + (tkn.gsub('1', '').size % 2).to_s
  9. end
  10. [bits].pack("B*")
  11. end
  12. end
  13. def apply_des(plain, keys)
  14. dec = OpenSSL::Cipher::DES.new
  15. keys.map {|k|
  16. dec.key = k
  17. dec.encrypt.update(plain)
  18. }
  19. end
  20. LM_MAGIC = "KGS!@\#$%"
  21. def lm_hash(password)
  22. keys = gen_keys password.upcase.ljust(14, "\0")
  23. apply_des(LM_MAGIC, keys).join
  24. end
  25. puts lm_hash "P@ssw0rd"

Source | RubyNTLM

Windows NTLMv1 Password hash

  1. require 'openssl'
  2. ntlmv1 = OpenSSL::Digest::MD4.hexdigest "P@ssw0rd".encode('UTF-16LE')
  3. puts ntlmv1

Windows NTLMv2 Password hash

  1. require 'openssl'
  2. ntlmv1 = OpenSSL::Digest::MD4.hexdigest "P@ssw0rd".encode('UTF-16LE')
  3. userdomain = "administrator".encode('UTF-16LE')
  4. ntlmv2 = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv1, userdomain)
  5. puts ntlmv2

MySQL Password hash

  1. puts "*" + Digest::SHA1.hexdigest(Digest::SHA1.digest('P@ssw0rd')).upcase

PostgreSQL Password hash

PostgreSQL hashes combined password and username then adds md5 in front of the hash

  1. require 'digest/md5'
  2. puts 'md5' + Digest::MD5.hexdigest('P@ssw0rd' + 'admin')

Symmetric Encryptions

To list all supported algorithms

  1. require 'openssl'
  2. puts OpenSSL::Cipher.ciphers

To unserdatand the cipher naming (eg. AES-128-CBC), it devided to 3 parts seperated by hyphen <Name>-<Key_length>-<Mode>

Symmetric encrption algorithms modes need 3 import data in order to work

  1. Key (password)
  2. Initial Vector (iv)
  3. Data to encrypt (plain text)

AES encryption

Encrypt

  1. require "openssl"
  2. data = 'Rubyfu Secret Mission: Go Hack The World!'
  3. # Setup the cipher
  4. cipher = OpenSSL::Cipher::AES.new('256-CBC') # Or use: OpenSSL::Cipher.new('AES-256-CBC')
  5. cipher.encrypt # Initializes the Cipher for encryption. (Must be called before key, iv, random_key, random_iv)
  6. key = cipher.random_key # If hard coded key, it must be 265-bits length
  7. iv = cipher.random_iv # Generate iv
  8. encrypted = cipher.update(data) + cipher.final # Finalize the encryption

Dencrypt

  1. decipher = OpenSSL::Cipher::AES.new('256-CBC') # Or use: OpenSSL::Cipher::Cipher.new('AES-256-CBC')
  2. decipher.decrypt # Initializes the Cipher for dencryption. (Must be called before key, iv, random_key, random_iv)
  3. decipher.key = key # Or generate secure random key: cipher.random_key
  4. decipher.iv = iv # Generate iv
  5. plain = decipher.update(encrypted) + decipher.final # Finalize the dencryption

Resources

Caesar cipher

Caesar cipher is one of the oldest known encryption methods. It is very simple - it is just shifting an alphabet. Transformation is termed ROTN, where N is shift value and ROT is from “ROTATE” because this is a cyclic shift.

In Ruby, array rotation is mutter of using rotate() method. So all what we need is to have array of all alphabets rotate it and map it with the original given string.

  1. #!/usb/bin/env ruby
  2. #
  3. # Caesar cipher
  4. #
  5. def caesar_cipher(string, shift=1)
  6. lowercase, uppercase = ('a'..'z').to_a, ('A'..'Z').to_a
  7. lower = lowercase.zip(lowercase.rotate(shift)).to_h
  8. upper = uppercase.zip(uppercase.rotate(shift)).to_h
  9. # One-liner: encrypter = ([*('a'..'z')].zip([*('a'..'z')].rotate(shift)) + [*('A'..'Z')].zip([*('A'..'Z')].rotate(shift))).to_h
  10. encrypter = lower.merge(upper)
  11. string.chars.map{|c| encrypter.fetch(c, c)}
  12. end
  13. string = ARGV[0]
  14. 1.upto(30) do |r|
  15. puts "ROT#{r}) " + caesar_cipher(string, r).join
  16. end

result

  1. $-> ruby caesar-cypher.rb Fipmti
  2. ROT1) Gjqnuj
  3. ROT2) Hkrovk
  4. ROT3) Ilspwl
  5. ROT4) Jmtqxm
  6. ROT5) Knuryn
  7. ROT6) Lovszo
  8. ROT7) Mpwtap
  9. ROT8) Nqxubq
  10. ROT9) Oryvcr
  11. ROT10) Pszwds
  12. ROT11) Qtaxet
  13. ROT12) Rubyfu <--
  14. ROT13) Svczgv
  15. ROT14) Twdahw
  16. ROT15) Uxebix
  17. ROT16) Vyfcjy
  18. ROT17) Wzgdkz
  19. ROT18) Xahela
  20. ROT19) Ybifmb
  21. ROT20) Zcjgnc
  22. ROT21) Adkhod
  23. ROT22) Belipe
  24. ROT23) Cfmjqf
  25. ROT24) Dgnkrg
  26. ROT25) Eholsh
  27. ROT26) Fipmti
  28. ROT27) Gjqnuj
  29. ROT28) Hkrovk
  30. ROT29) Ilspwl
  31. ROT30) Jmtqxm

Sources:

Enigma script

Cryptography - 图1
Figure 1. Enigma machine diagram
  1. Plugboard = Hash[*('A'..'Z').to_a.shuffle.first(20)]
  2. Plugboard.merge!(Plugboard.invert)
  3. Plugboard.default_proc = proc { |hash, key| key }
  4. def build_a_rotor
  5. Hash[('A'..'Z').zip(('A'..'Z').to_a.shuffle)]
  6. end
  7. Rotor_1, Rotor_2, Rotor_3 = build_a_rotor, build_a_rotor, build_a_rotor
  8. Reflector = Hash[*('A'..'Z').to_a.shuffle]
  9. Reflector.merge!(Reflector.invert)
  10. def input(string)
  11. rotor_1, rotor_2, rotor_3 = Rotor_1.dup, Rotor_2.dup, Rotor_3.dup
  12. string.chars.each_with_index.map do |char, index|
  13. rotor_1 = rotate_rotor rotor_1
  14. rotor_2 = rotate_rotor rotor_2 if index % 25 == 0
  15. rotor_3 = rotate_rotor rotor_3 if index % 25*25 == 0
  16. char = Plugboard[char]
  17. char = rotor_1[char]
  18. char = rotor_2[char]
  19. char = rotor_3[char]
  20. char = Reflector[char]
  21. char = rotor_3.invert[char]
  22. char = rotor_2.invert[char]
  23. char = rotor_1.invert[char]
  24. Plugboard[char]
  25. end.join
  26. end
  27. def rotate_rotor(rotor)
  28. Hash[rotor.map { |k,v| [k == 'Z' ? 'A' : k.next, v] }]
  29. end
  30. plain_text = 'IHAVETAKENMOREOUTOFALCOHOLTHANALCOHOLHASTAKENOUTOFME'
  31. puts "Encrypted '#{plain_text}' to '#{encrypted = input(plain_text)}'"
  32. puts "Decrypted '#{encrypted}' to '#{decrypted = input(encrypted)}'"
  33. puts 'Success!' if plain_text == decrypted

Source | Understanding the Enigma machine with 30 lines of Ruby