Cryptography

Generating Hashes

MD5 hash

1
require 'digest'
2
puts Digest::MD5.hexdigest '[email protected]'
Copied!

SHA1 hash

1
require 'digest'
2
puts Digest::SHA1.hexdigest '[email protected]'
Copied!

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
3
# 1
4
sha2_256 = Digest::SHA2.new(bitlen = 256) # bitlen could be 256, 384, 512
5
sha2_256.hexdigest '[email protected]'
6
7
# 2
8
Digest::SHA2.new(bitlen = 256).hexdigest '[email protected]'
Copied!
Way #2: By Using the class directly
1
require 'digest'
2
puts Digest::SHA256.hexdigest '[email protected]'
3
puts Digest::SHA384.hexdigest '[email protected]'
4
puts Digest::SHA512.hexdigest '[email protected]'
Copied!
Bonus: Generate Linux-like Shadow password
1
require 'digest/sha2'
2
password = '[email protected]'
3
salt = rand(36**8).to_s(36)
4
shadow_hash = password.crypt("$6quot; + salt)
Copied!

Windows LM Password hash

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

Windows NTLMv1 Password hash

1
require 'openssl'
2
ntlmv1 = OpenSSL::Digest::MD4.hexdigest "[email protected]".encode('UTF-16LE')
3
puts ntlmv1
Copied!

Windows NTLMv2 Password hash

1
require 'openssl'
2
ntlmv1 = OpenSSL::Digest::MD4.hexdigest "[email protected]".encode('UTF-16LE')
3
userdomain = "administrator".encode('UTF-16LE')
4
ntlmv2 = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv1, userdomain)
5
puts ntlmv2
Copied!

MySQL Password hash

1
puts "*" + Digest::SHA1.hexdigest(Digest::SHA1.digest('[email protected]')).upcase
Copied!

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('[email protected]' + 'admin')
Copied!

Symmetric Encryptions

To list all supported algorithms
1
require 'openssl'
2
puts OpenSSL::Cipher.ciphers
Copied!
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
3
data = 'Rubyfu Secret Mission: Go Hack The World!'
4
5
# Setup the cipher
6
cipher = OpenSSL::Cipher::AES.new('256-CBC') # Or use: OpenSSL::Cipher.new('AES-256-CBC')
7
cipher.encrypt # Initializes the Cipher for encryption. (Must be called before key, iv, random_key, random_iv)
8
key = cipher.random_key # If hard coded key, it must be 265-bits length
9
iv = cipher.random_iv # Generate iv
10
encrypted = cipher.update(data) + cipher.final # Finalize the encryption
Copied!

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
Copied!
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
6
def caesar_cipher(string, shift=1)
7
lowercase, uppercase = ('a'..'z').to_a, ('A'..'Z').to_a
8
lower = lowercase.zip(lowercase.rotate(shift)).to_h
9
upper = uppercase.zip(uppercase.rotate(shift)).to_h
10
11
# One-liner: encrypter = ([*('a'..'z')].zip([*('a'..'z')].rotate(shift)) + [*('A'..'Z')].zip([*('A'..'Z')].rotate(shift))).to_h
12
encrypter = lower.merge(upper)
13
string.chars.map{|c| encrypter.fetch(c, c)}
14
end
15
16
string = ARGV[0]
17
1.upto(30) do |r|
18
puts "ROT#{r}) " + caesar_cipher(string, r).join
19
end
Copied!
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
Copied!
Sources:

Enigma script

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
5
def build_a_rotor
6
Hash[('A'..'Z').zip(('A'..'Z').to_a.shuffle)]
7
end
8
9
Rotor_1, Rotor_2, Rotor_3 = build_a_rotor, build_a_rotor, build_a_rotor
10
11
Reflector = Hash[*('A'..'Z').to_a.shuffle]
12
Reflector.merge!(Reflector.invert)
13
14
def input(string)
15
rotor_1, rotor_2, rotor_3 = Rotor_1.dup, Rotor_2.dup, Rotor_3.dup
16
17
string.chars.each_with_index.map do |char, index|
18
rotor_1 = rotate_rotor rotor_1
19
rotor_2 = rotate_rotor rotor_2 if index % 25 == 0
20
rotor_3 = rotate_rotor rotor_3 if index % 25*25 == 0
21
22
char = Plugboard[char]
23
24
char = rotor_1[char]
25
char = rotor_2[char]
26
char = rotor_3[char]
27
28
char = Reflector[char]
29
30
char = rotor_3.invert[char]
31
char = rotor_2.invert[char]
32
char = rotor_1.invert[char]
33
34
Plugboard[char]
35
end.join
36
end
37
38
def rotate_rotor(rotor)
39
Hash[rotor.map { |k,v| [k == 'Z' ? 'A' : k.next, v] }]
40
end
41
42
plain_text = 'IHAVETAKENMOREOUTOFALCOHOLTHANALCOHOLHASTAKENOUTOFME'
43
puts "Encrypted '#{plain_text}' to '#{encrypted = input(plain_text)}'"
44
puts "Decrypted '#{encrypted}' to '#{decrypted = input(encrypted)}'"
45
puts 'Success!' if plain_text == decrypted
Copied!
Last modified 5mo ago