crypto_toolchain 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +51 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Guardfile +15 -0
- data/LICENSE +21 -0
- data/README.md +95 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/crypto_toolchain.gemspec +33 -0
- data/exe/crypto +7 -0
- data/lib/crypto_toolchain/black_boxes/aes_ctr_editor.rb +25 -0
- data/lib/crypto_toolchain/black_boxes/cbc_bitflip_target.rb +33 -0
- data/lib/crypto_toolchain/black_boxes/cbc_iv_equals_key_target.rb +35 -0
- data/lib/crypto_toolchain/black_boxes/cbc_padding_oracle.rb +44 -0
- data/lib/crypto_toolchain/black_boxes/ctr_bitflip_target.rb +32 -0
- data/lib/crypto_toolchain/black_boxes/dsa_keypair.rb +50 -0
- data/lib/crypto_toolchain/black_boxes/ecb_cut_and_paste_target.rb +50 -0
- data/lib/crypto_toolchain/black_boxes/ecb_interpolate_chosen_plaintext_oracle.rb +28 -0
- data/lib/crypto_toolchain/black_boxes/ecb_or_cbc_encryptor.rb +47 -0
- data/lib/crypto_toolchain/black_boxes/ecb_prepend_chosen_plaintext_oracle.rb +23 -0
- data/lib/crypto_toolchain/black_boxes/md4_mac.rb +20 -0
- data/lib/crypto_toolchain/black_boxes/mt_19937_stream_cipher.rb +47 -0
- data/lib/crypto_toolchain/black_boxes/netcat_cbc_padding_oracle.rb +33 -0
- data/lib/crypto_toolchain/black_boxes/rsa_keypair.rb +83 -0
- data/lib/crypto_toolchain/black_boxes/rsa_parity_oracle.rb +14 -0
- data/lib/crypto_toolchain/black_boxes/rsa_unpadded_message_recovery_oracle.rb +24 -0
- data/lib/crypto_toolchain/black_boxes/sha1_mac.rb +20 -0
- data/lib/crypto_toolchain/black_boxes.rb +22 -0
- data/lib/crypto_toolchain/diffie_hellman/messages.rb +53 -0
- data/lib/crypto_toolchain/diffie_hellman/mitm.rb +52 -0
- data/lib/crypto_toolchain/diffie_hellman/peer.rb +130 -0
- data/lib/crypto_toolchain/diffie_hellman/peer_info.rb +43 -0
- data/lib/crypto_toolchain/diffie_hellman/received_message.rb +17 -0
- data/lib/crypto_toolchain/diffie_hellman.rb +10 -0
- data/lib/crypto_toolchain/extensions/integer_extensions.rb +90 -0
- data/lib/crypto_toolchain/extensions/object_extensions.rb +24 -0
- data/lib/crypto_toolchain/extensions/string_extensions.rb +263 -0
- data/lib/crypto_toolchain/extensions.rb +8 -0
- data/lib/crypto_toolchain/srp/client.rb +51 -0
- data/lib/crypto_toolchain/srp/framework.rb +55 -0
- data/lib/crypto_toolchain/srp/server.rb +38 -0
- data/lib/crypto_toolchain/srp/simple_client.rb +32 -0
- data/lib/crypto_toolchain/srp/simple_server.rb +68 -0
- data/lib/crypto_toolchain/srp.rb +14 -0
- data/lib/crypto_toolchain/tools/aes_ctr_recoverer.rb +30 -0
- data/lib/crypto_toolchain/tools/cbc_bitflip_attack.rb +30 -0
- data/lib/crypto_toolchain/tools/cbc_iv_equals_key_attack.rb +30 -0
- data/lib/crypto_toolchain/tools/cbc_padding_oracle_attack.rb +51 -0
- data/lib/crypto_toolchain/tools/ctr_bitflip_attack.rb +24 -0
- data/lib/crypto_toolchain/tools/determine_blocksize.rb +20 -0
- data/lib/crypto_toolchain/tools/dsa_recover_nonce_from_signatures.rb +53 -0
- data/lib/crypto_toolchain/tools/dsa_recover_private_key_from_nonce.rb +39 -0
- data/lib/crypto_toolchain/tools/ecb_cut_and_paste_attack.rb +47 -0
- data/lib/crypto_toolchain/tools/ecb_interpolate_chosen_plaintext_attack.rb +72 -0
- data/lib/crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack.rb +42 -0
- data/lib/crypto_toolchain/tools/interactive_xor.rb +51 -0
- data/lib/crypto_toolchain/tools/low_exponent_rsa_signature_forgery.rb +27 -0
- data/lib/crypto_toolchain/tools/md4_length_extension_attack.rb +30 -0
- data/lib/crypto_toolchain/tools/mt_19937_seed_recoverer.rb +27 -0
- data/lib/crypto_toolchain/tools/mt_19937_stream_cipher_seed_recoverer.rb +40 -0
- data/lib/crypto_toolchain/tools/rsa_broadcast_attack.rb +21 -0
- data/lib/crypto_toolchain/tools/rsa_parity_oracle_attack.rb +33 -0
- data/lib/crypto_toolchain/tools/rsa_unpadded_message_recovery_attack.rb +49 -0
- data/lib/crypto_toolchain/tools/sha1_length_extension_attack.rb +30 -0
- data/lib/crypto_toolchain/tools.rb +31 -0
- data/lib/crypto_toolchain/utilities/hmac.rb +73 -0
- data/lib/crypto_toolchain/utilities/md4.rb +106 -0
- data/lib/crypto_toolchain/utilities/mt_19937.rb +218 -0
- data/lib/crypto_toolchain/utilities/sha1.rb +95 -0
- data/lib/crypto_toolchain/utilities.rb +9 -0
- data/lib/crypto_toolchain/version.rb +3 -0
- data/lib/crypto_toolchain.rb +34 -0
- metadata +232 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module Utilities
|
3
|
+
class HMAC
|
4
|
+
class << self
|
5
|
+
def digest(message, key: , hash: CryptoToolchain::Utilities::SHA1)
|
6
|
+
new(key: key, hash: hash).digest(message)
|
7
|
+
end
|
8
|
+
|
9
|
+
def hexdigest(message, key: , hash: CryptoToolchain::Utilities::SHA1)
|
10
|
+
new(key: key, hash: hash).hexdigest(message)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(key: , hash: , blocksize: nil)
|
16
|
+
@key = key
|
17
|
+
@hash = hash
|
18
|
+
@blocksize = blocksize || determine_blocksize
|
19
|
+
end
|
20
|
+
|
21
|
+
def digest(message)
|
22
|
+
hash.digest(outer_pad + hash.digest(inner_pad + message))
|
23
|
+
end
|
24
|
+
|
25
|
+
def hexdigest(message)
|
26
|
+
digest(message).to_hex
|
27
|
+
end
|
28
|
+
|
29
|
+
def determine_blocksize
|
30
|
+
case hash.to_s.split(':').last.downcase.gsub(/[^a-z0-9]/i, '')
|
31
|
+
when /md(4|5)/
|
32
|
+
64
|
33
|
+
when /sha(1|224|256)/
|
34
|
+
64
|
35
|
+
else
|
36
|
+
raise ArgumentError.new("Unsupported hash #{hash}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def outer_pad
|
43
|
+
@outer_pad ||= (0x5c.chr * blocksize) ^ blocksize_key
|
44
|
+
end
|
45
|
+
|
46
|
+
def inner_pad
|
47
|
+
@inner_pad ||= (0x36.chr * blocksize) ^ blocksize_key
|
48
|
+
end
|
49
|
+
|
50
|
+
def blocksize_key
|
51
|
+
@blocksize_key ||= padded(shortened(key))
|
52
|
+
end
|
53
|
+
|
54
|
+
def padded(input)
|
55
|
+
if input.bytesize < blocksize
|
56
|
+
input.ljust(blocksize, 0.chr)
|
57
|
+
else
|
58
|
+
input
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def shortened(input)
|
63
|
+
if input.bytesize > blocksize
|
64
|
+
hash.digest(input)
|
65
|
+
else
|
66
|
+
input
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_reader :blocksize, :key, :hash
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#encoding: ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module Utilities
|
4
|
+
class MD4
|
5
|
+
class << self
|
6
|
+
def hexdigest(str, state: INITIAL_STATE, append_length: 0 )
|
7
|
+
CryptoToolchain::Utilities::MD4.new(str).hexdigest(state: state, append_length: append_length)
|
8
|
+
end
|
9
|
+
|
10
|
+
def bindigest(str, state: INITIAL_STATE, append_length: 0)
|
11
|
+
CryptoToolchain::Utilities::MD4.new(str).bindigest(state: state, append_length: append_length)
|
12
|
+
end
|
13
|
+
alias_method :digest, :bindigest
|
14
|
+
|
15
|
+
def padding(str)
|
16
|
+
num_null_pad = (56 - (str.bytesize + 1) ) % 64
|
17
|
+
0x80.chr + (0.chr * num_null_pad) + [(str.bytesize * 8)].pack("Q<")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(message)
|
22
|
+
@original = message
|
23
|
+
end
|
24
|
+
|
25
|
+
def hexdigest(state: INITIAL_STATE, append_length: 0)
|
26
|
+
bindigest(state: state, append_length: append_length).unpack("H*").join
|
27
|
+
end
|
28
|
+
|
29
|
+
def bindigest(state: INITIAL_STATE, append_length: 0)
|
30
|
+
running_state = registers_from(state)
|
31
|
+
|
32
|
+
length = original.bytesize + append_length
|
33
|
+
|
34
|
+
padding_len = (56 - (length + 1) ) % 64
|
35
|
+
str_length = [(length * 8)].pack("Q<")
|
36
|
+
padding = (0x80.chr + (0.chr * padding_len) + str_length)
|
37
|
+
|
38
|
+
(original + padding).in_blocks(64).each do |block|
|
39
|
+
w = block.unpack("L<16")
|
40
|
+
|
41
|
+
a, b, c, d = running_state
|
42
|
+
# Extraction of each 16-operation round into a loop over four elements originally
|
43
|
+
# found at https://rosettacode.org/wiki/MD4#Ruby
|
44
|
+
[0, 4, 8, 12].each do |i|
|
45
|
+
a = f(a, b, c, d, w[i]).lrot(3)
|
46
|
+
d = f(d, a, b, c, w[i+1]).lrot(7)
|
47
|
+
c = f(c, d, a, b, w[i+2]).lrot(11)
|
48
|
+
b = f(b, c, d, a, w[i+3]).lrot(19)
|
49
|
+
end
|
50
|
+
[0, 1, 2, 3].each do |i|
|
51
|
+
a = g(a, b, c, d, w[i]).lrot(3)
|
52
|
+
d = g(d, a, b, c, w[i+4]).lrot(5)
|
53
|
+
c = g(c, d, a, b, w[i+8]).lrot(9)
|
54
|
+
b = g(b, c, d, a, w[i+12]).lrot(13)
|
55
|
+
end
|
56
|
+
[0, 2, 1, 3].each do |i|
|
57
|
+
a = h(a, b, c, d, w[i]).lrot(3)
|
58
|
+
d = h(d, a, b, c, w[i+8]).lrot(9)
|
59
|
+
c = h(c, d, a, b, w[i+4]).lrot(11)
|
60
|
+
b = h(b, c, d, a, w[i+12]).lrot(15)
|
61
|
+
end
|
62
|
+
|
63
|
+
[a, b, c, d].each_with_index do |val, i|
|
64
|
+
running_state[i] = (running_state[i] + val) & 0xffffffff
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
running_state.pack("L<4")
|
69
|
+
end
|
70
|
+
alias_method :digest, :bindigest
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :original
|
75
|
+
|
76
|
+
def f(arg, x, y, z, block)
|
77
|
+
arg +
|
78
|
+
((x & y) | (~x & z)) +
|
79
|
+
block
|
80
|
+
end
|
81
|
+
|
82
|
+
def g(arg, x, y, z, block)
|
83
|
+
arg +
|
84
|
+
((x & y) | (x & z) | (y & z)) +
|
85
|
+
block +
|
86
|
+
0x5a827999
|
87
|
+
end
|
88
|
+
|
89
|
+
def h(arg, x, y, z, block)
|
90
|
+
arg +
|
91
|
+
(x ^ y ^ z) +
|
92
|
+
block +
|
93
|
+
0x6ed9eba1
|
94
|
+
end
|
95
|
+
|
96
|
+
# Equivalent to [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 ]
|
97
|
+
INITIAL_STATE = "0123456789abcdeffedcba9876543210"
|
98
|
+
|
99
|
+
def registers_from(hex_str)
|
100
|
+
raise ArgumentError.new("Argument must be a hex string") unless hex_str.hex?
|
101
|
+
raise ArgumentError.new("Argument must be 32 characters long") unless hex_str.length == 32
|
102
|
+
hex_str.from_hex.unpack("L<4")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
# Note: 64 bit is untested
|
4
|
+
module CryptoToolchain
|
5
|
+
module Utilities
|
6
|
+
class MT19937
|
7
|
+
PARAMETERS_32 = {
|
8
|
+
w: 32, n: 624, m: 397, r: 31,
|
9
|
+
a: 0x9908b0df,
|
10
|
+
u: 11, d: 0xFFFFFFFF,
|
11
|
+
s: 7, b: 0x9d2c5680,
|
12
|
+
t: 15, c: 0xefc60000,
|
13
|
+
l: 18,
|
14
|
+
f: 1812433253
|
15
|
+
}.freeze
|
16
|
+
PARAMETERS_64 = {
|
17
|
+
w: 64, n: 312, m: 156, r: 31,
|
18
|
+
a: 0xB5026F5AA96619E9,
|
19
|
+
u: 29, d: 0x5555555555555555,
|
20
|
+
s: 17, b: 0x71D67FFFEDA60000,
|
21
|
+
t: 37, c: 0xFFF7EEE000000000,
|
22
|
+
l: 43,
|
23
|
+
f: 6364136223846793005
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
def self.from_array(arr, bits: 32, index: parameters_for(bits).fetch(:n))
|
27
|
+
mt = new(0, bits: bits)
|
28
|
+
mt.send(:state=, arr)
|
29
|
+
mt.send(:index=, index)
|
30
|
+
mt
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.parameters_for(bits)
|
34
|
+
case bits
|
35
|
+
when 32
|
36
|
+
PARAMETERS_32
|
37
|
+
when 64
|
38
|
+
PARAMETERS_64
|
39
|
+
else
|
40
|
+
raise ArgumentError.new("Bits must be 32 or 64")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(seed, bits: 32)
|
45
|
+
@seed = seed
|
46
|
+
set_vars!(self.class.parameters_for(bits))
|
47
|
+
@index = n
|
48
|
+
@state = build_state!
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
return false unless other.is_a?(self.class)
|
53
|
+
other.send(:state) == state && other.send(:index) == index
|
54
|
+
end
|
55
|
+
|
56
|
+
def extract
|
57
|
+
twist! if index >= n
|
58
|
+
temper(state[index])
|
59
|
+
ensure
|
60
|
+
@index += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def temper(y)
|
64
|
+
y ^= (y >> u) & d
|
65
|
+
y ^= (y << s) & b
|
66
|
+
y ^= (y << t) & c
|
67
|
+
y ^= (y >> l)
|
68
|
+
lowest_bits(y)
|
69
|
+
end
|
70
|
+
|
71
|
+
def untemper(y)
|
72
|
+
y = untemper_rshift(y, shift: l)
|
73
|
+
y = untemper_lshift(y, shift: t, mask: c)
|
74
|
+
y = untemper_lshift(y, shift: s, mask: b)
|
75
|
+
untemper_rshift(y, shift: u, mask: d)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
attr_reader(*(PARAMETERS_32.keys))
|
81
|
+
attr_accessor :seed, :state, :index
|
82
|
+
|
83
|
+
# General principle:
|
84
|
+
# x ^= (x << y) is periodic.
|
85
|
+
#
|
86
|
+
# What we want to do, then, is exploit this periodicity:
|
87
|
+
# a -> b -> c -> d
|
88
|
+
# ^ v
|
89
|
+
# |------<-------|
|
90
|
+
# Where the temper function went from c -> d, we want to go d->a->b->c to untemper
|
91
|
+
# So we do the most naive thing possible, rather than the performant method below which never quite
|
92
|
+
# clicked in the ol' brain
|
93
|
+
def untemper_lshift(val, shift: , mask: 0xffffffff)
|
94
|
+
original = val
|
95
|
+
loop do
|
96
|
+
prev = val
|
97
|
+
val ^= ((val << shift) & mask)
|
98
|
+
return prev if val == original
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def untemper_rshift(val, shift: , mask: 0xffffffff)
|
103
|
+
original = val
|
104
|
+
loop do
|
105
|
+
prev = val
|
106
|
+
val ^= ((val >> shift) & mask)
|
107
|
+
return prev if val == original
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def defunct_untemper_step_for_posterity(y, debug: false)
|
112
|
+
# We're reversing
|
113
|
+
# y ^= (y << 7) & 0x9d2cf80
|
114
|
+
# so, take the bottom 25 bits of y, shift them over, and & that with the constant 0x9d2c5680,
|
115
|
+
# and xor the result with the top 25 bits of y. Notably, this leaves the bottom 7 bits of y
|
116
|
+
# untouched. The general idea is that we iteratively recover bits. The input shares the bottom 7
|
117
|
+
# bits with the proper output. We work in 7-bit chunks (the last chunk is only 4 bits of course),
|
118
|
+
# shifting and xor-ing (and &ing with the appropriate chunk of the mask) as we go.
|
119
|
+
#
|
120
|
+
# This algorithm never has varying periodicity, unlike the brute force method above. My current
|
121
|
+
# thought is that this is because I'm not appropriately breaking the mask up into chunks like I do
|
122
|
+
# here, but I'm not quite sure. For now, I'll stick with the naive algorithm until I have a complete
|
123
|
+
# understanding of this one.
|
124
|
+
if debug
|
125
|
+
puts " y #{y.to_bits} #{y}"
|
126
|
+
puts
|
127
|
+
puts "y<<7 #{((y<<7) & 0xffffffff).to_bits}"
|
128
|
+
puts "&with #{(0x00003f80 & b).to_bits}"
|
129
|
+
puts " = #{((y << 7) & (0x00003f80 & b)).to_bits}"
|
130
|
+
puts "xor y #{y.to_bits}"
|
131
|
+
end
|
132
|
+
|
133
|
+
y ^= (y << 7) & (0x00003f80 & b)
|
134
|
+
|
135
|
+
if debug
|
136
|
+
puts " = #{y.to_bits}"
|
137
|
+
puts
|
138
|
+
puts "y<<7 #{((y<<7) & 0xffffffff).to_bits}"
|
139
|
+
puts "&with #{(0x001fc000 & b).to_bits}"
|
140
|
+
puts " = #{((y << 7) & (0x001fc000 & b)).to_bits}"
|
141
|
+
puts "xor y #{y.to_bits}"
|
142
|
+
end
|
143
|
+
|
144
|
+
y ^= (y << 7) & (0x001fc000 & b)
|
145
|
+
|
146
|
+
if debug
|
147
|
+
puts " = #{y.to_bits}"
|
148
|
+
puts
|
149
|
+
puts "y<<7 #{((y<<7) & 0xffffffff).to_bits}"
|
150
|
+
puts "&with #{(0x0fe00000 & b).to_bits}"
|
151
|
+
puts " = #{((y << 7) & (0x0fe00000 & b)).to_bits}"
|
152
|
+
puts "xor y #{y.to_bits}"
|
153
|
+
end
|
154
|
+
|
155
|
+
y ^= (y << 7) & (0x0fe00000 & b)
|
156
|
+
|
157
|
+
if debug
|
158
|
+
puts " = #{y.to_bits}"
|
159
|
+
puts
|
160
|
+
puts "y<<7 #{((y<<7) & 0xffffffff).to_bits}"
|
161
|
+
puts "&with #{(0xf0000000 & b).to_bits}"
|
162
|
+
puts " = #{((y << 7) & (0xf0000000 & b)).to_bits}"
|
163
|
+
puts "xor y #{y.to_bits}"
|
164
|
+
end
|
165
|
+
|
166
|
+
y ^= (y << 7) & (0xf0000000 & b)
|
167
|
+
|
168
|
+
if debug
|
169
|
+
puts " = #{y.to_bits}"
|
170
|
+
puts y
|
171
|
+
end
|
172
|
+
y
|
173
|
+
end
|
174
|
+
|
175
|
+
def build_state!
|
176
|
+
_state = [seed]
|
177
|
+
for i in (1...n)
|
178
|
+
prev = _state[i - 1]
|
179
|
+
val = lowest_bits((f * (prev ^ (prev >> (w-2)) ) + i))
|
180
|
+
_state << val
|
181
|
+
end
|
182
|
+
_state
|
183
|
+
end
|
184
|
+
|
185
|
+
def twist!
|
186
|
+
for i in (0...n)
|
187
|
+
cur = state[i]
|
188
|
+
x = (cur & upper_mask) + (state[(i+1) % n] & lower_mask)
|
189
|
+
xA = x >> 1
|
190
|
+
if (x % 2) != 0
|
191
|
+
xA = xA ^ a
|
192
|
+
end
|
193
|
+
state[i] = state[(i + m) % n] ^ xA
|
194
|
+
end
|
195
|
+
@index = 0
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
|
199
|
+
def lower_mask
|
200
|
+
@lower_mask ||= (1 << r) - 1
|
201
|
+
end
|
202
|
+
|
203
|
+
def upper_mask
|
204
|
+
@upper_mask ||= lowest_bits(~lower_mask)
|
205
|
+
end
|
206
|
+
|
207
|
+
def set_vars!(parameters)
|
208
|
+
parameters.each do |k, v|
|
209
|
+
instance_variable_set("@#{k}", v)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def lowest_bits(num)
|
214
|
+
num & 0xffffffff
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#encoding: ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module Utilities
|
4
|
+
class SHA1
|
5
|
+
class << self
|
6
|
+
def hexdigest(str, state: INITIAL_STATE, append_length: 0 )
|
7
|
+
CryptoToolchain::Utilities::SHA1.new(str).hexdigest(state: state, append_length: append_length)
|
8
|
+
end
|
9
|
+
|
10
|
+
def bindigest(str, state: INITIAL_STATE, append_length: 0)
|
11
|
+
CryptoToolchain::Utilities::SHA1.new(str).bindigest(state: state, append_length: append_length)
|
12
|
+
end
|
13
|
+
alias_method :digest, :bindigest
|
14
|
+
|
15
|
+
def padding(str)
|
16
|
+
num_null_pad = (56 - (str.bytesize + 1) ) % 64
|
17
|
+
0x80.chr + (0.chr * num_null_pad) + [str.bytesize * 8].pack("Q>")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(message)
|
22
|
+
@original = message
|
23
|
+
end
|
24
|
+
|
25
|
+
def hexdigest(state: INITIAL_STATE, append_length: 0)
|
26
|
+
bindigest(state: state, append_length: append_length).unpack("H*").join
|
27
|
+
end
|
28
|
+
|
29
|
+
def bindigest(state: INITIAL_STATE, append_length: 0)
|
30
|
+
h = registers_from(state).dup
|
31
|
+
|
32
|
+
length = original.bytesize + append_length
|
33
|
+
|
34
|
+
# while (string.size % 64) != 56
|
35
|
+
num_null_pad = (56 - (length + 1) ) % 64
|
36
|
+
padding = 0x80.chr + (0.chr * num_null_pad) + [length * 8].pack("Q>")
|
37
|
+
|
38
|
+
(original + padding).in_blocks(64).each do |_block|
|
39
|
+
w = _block.unpack("L>16")
|
40
|
+
(16..79).each do |i|
|
41
|
+
w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]).lrot(1)
|
42
|
+
end
|
43
|
+
|
44
|
+
a, b, c, d, e = h
|
45
|
+
|
46
|
+
(0..79).each do |i|
|
47
|
+
func, k = f_and_k_for(i)
|
48
|
+
f = func.call(b, c, d)
|
49
|
+
temp = (a.lrot(5) + f + e + k + w[i]) & 0xffffffff
|
50
|
+
e = d
|
51
|
+
d = c
|
52
|
+
c = b.lrot(30)
|
53
|
+
b = a
|
54
|
+
a = temp
|
55
|
+
end
|
56
|
+
|
57
|
+
[a, b, c, d, e].each_with_index do |val, i|
|
58
|
+
h[i] = (h[i] + val) & 0xffffffff
|
59
|
+
end
|
60
|
+
end
|
61
|
+
h.pack("L>5")
|
62
|
+
end
|
63
|
+
alias_method :digest, :bindigest
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
attr_reader :original
|
68
|
+
|
69
|
+
F_FUNCTIONS = [
|
70
|
+
->(b,c,d) { (b & c) | ((~b) & d) },
|
71
|
+
->(b,c,d) { b ^ c ^ d },
|
72
|
+
->(b,c,d) { (b & c) | (b & d) | (c & d) },
|
73
|
+
->(b,c,d) { b ^ c ^ d },
|
74
|
+
].freeze
|
75
|
+
|
76
|
+
K_CONSTANTS = [ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ].freeze
|
77
|
+
|
78
|
+
CONSTANTS = F_FUNCTIONS.zip(K_CONSTANTS).freeze
|
79
|
+
|
80
|
+
# Equivalent to [ 0x67452301, 0xefcdaB89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ] when using registers
|
81
|
+
INITIAL_STATE = "67452301efcdab8998badcfe10325476c3d2e1f0".freeze
|
82
|
+
|
83
|
+
def registers_from(hex_str)
|
84
|
+
raise ArgumentError.new("Argument must be a hex string") unless hex_str.hex?
|
85
|
+
raise ArgumentError.new("Argument must be 40 characters long") unless hex_str.length == 40
|
86
|
+
hex_str.from_hex.unpack("L>*")
|
87
|
+
end
|
88
|
+
|
89
|
+
def f_and_k_for(i)
|
90
|
+
raise ArgumentError.new("i must be in 0..79") unless i >=0 && i <= 79
|
91
|
+
CONSTANTS[i/20]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require "base64"
|
4
|
+
require "pry-byebug"
|
5
|
+
require "pp"
|
6
|
+
require "uri"
|
7
|
+
require 'json'
|
8
|
+
require 'securerandom'
|
9
|
+
require "bigdecimal"
|
10
|
+
require "crypto_toolchain/version"
|
11
|
+
require "crypto_toolchain/extensions"
|
12
|
+
require "crypto_toolchain/utilities"
|
13
|
+
require "crypto_toolchain/tools"
|
14
|
+
require "crypto_toolchain/black_boxes"
|
15
|
+
require "crypto_toolchain/diffie_hellman"
|
16
|
+
require "crypto_toolchain/srp"
|
17
|
+
|
18
|
+
module CryptoToolchain
|
19
|
+
AES_BLOCK_SIZE = 16
|
20
|
+
PRINTABLE_CHARACTERS = ((0x20..0x7e).to_a + [0x0a, 0x0d]).map(&:chr).freeze
|
21
|
+
NIST_P = 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff
|
22
|
+
NIST_G = 2
|
23
|
+
ASN1 = {
|
24
|
+
md5: "0 0\f\x06\b*\x86H\x86\xF7\r\x02\x05\x05\x00\x04\x10",
|
25
|
+
sha1: "0!0\t\x06\x05+\x0E\x03\x02\x1A\x05\x00\x04\x14",
|
26
|
+
sha256: "010\r\x06\t`\x86H\x01e\x03\x04\x02\x01\x05\x00\x04 ",
|
27
|
+
sha384: "0A0\r\x06\t`\x86H\x01e\x03\x04\x02\x02\x05\x00\x040",
|
28
|
+
sha512: "0Q0\r\x06\t`\x86H\x01e\x03\x04\x02\x03\x05\x00\x04@"
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
DSA_P = 0x800000000000000089e1855218a0e7dac38136ffafa72eda7859f2171e25e65eac698c1702578b07dc2a1076da241c76c62d374d8389ea5aeffd3226a0530cc565f3bf6b50929139ebeac04f48c3c84afb796d61e5a4f9a8fda812ab59494232c7d2b4deb50aa18ee9e132bfa85ac4374d7f9091abc3d015efc871a584471bb1
|
32
|
+
DSA_Q = 0xf4f47f05794b256174bba6e9b396a7707e563c5b
|
33
|
+
DSA_G = 0x5958c9d3898b224b12672c0b98e06c60df923cb8bc999d119458fef538b8fa4046c8db53039db620c094c9fa077ef389b5322a559946a71903f990f1f7e0e025e2d7f7cf494aff1a0470f5b64c36b625a097f1651fe775323556fe00b3608c887892878480e99041be601a62166ca6894bdd41a7054ec89f756ba9fc95302291
|
34
|
+
end
|