crypto_toolchain 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +51 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +3 -0
  6. data/Guardfile +15 -0
  7. data/LICENSE +21 -0
  8. data/README.md +95 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/crypto_toolchain.gemspec +33 -0
  13. data/exe/crypto +7 -0
  14. data/lib/crypto_toolchain/black_boxes/aes_ctr_editor.rb +25 -0
  15. data/lib/crypto_toolchain/black_boxes/cbc_bitflip_target.rb +33 -0
  16. data/lib/crypto_toolchain/black_boxes/cbc_iv_equals_key_target.rb +35 -0
  17. data/lib/crypto_toolchain/black_boxes/cbc_padding_oracle.rb +44 -0
  18. data/lib/crypto_toolchain/black_boxes/ctr_bitflip_target.rb +32 -0
  19. data/lib/crypto_toolchain/black_boxes/dsa_keypair.rb +50 -0
  20. data/lib/crypto_toolchain/black_boxes/ecb_cut_and_paste_target.rb +50 -0
  21. data/lib/crypto_toolchain/black_boxes/ecb_interpolate_chosen_plaintext_oracle.rb +28 -0
  22. data/lib/crypto_toolchain/black_boxes/ecb_or_cbc_encryptor.rb +47 -0
  23. data/lib/crypto_toolchain/black_boxes/ecb_prepend_chosen_plaintext_oracle.rb +23 -0
  24. data/lib/crypto_toolchain/black_boxes/md4_mac.rb +20 -0
  25. data/lib/crypto_toolchain/black_boxes/mt_19937_stream_cipher.rb +47 -0
  26. data/lib/crypto_toolchain/black_boxes/netcat_cbc_padding_oracle.rb +33 -0
  27. data/lib/crypto_toolchain/black_boxes/rsa_keypair.rb +83 -0
  28. data/lib/crypto_toolchain/black_boxes/rsa_parity_oracle.rb +14 -0
  29. data/lib/crypto_toolchain/black_boxes/rsa_unpadded_message_recovery_oracle.rb +24 -0
  30. data/lib/crypto_toolchain/black_boxes/sha1_mac.rb +20 -0
  31. data/lib/crypto_toolchain/black_boxes.rb +22 -0
  32. data/lib/crypto_toolchain/diffie_hellman/messages.rb +53 -0
  33. data/lib/crypto_toolchain/diffie_hellman/mitm.rb +52 -0
  34. data/lib/crypto_toolchain/diffie_hellman/peer.rb +130 -0
  35. data/lib/crypto_toolchain/diffie_hellman/peer_info.rb +43 -0
  36. data/lib/crypto_toolchain/diffie_hellman/received_message.rb +17 -0
  37. data/lib/crypto_toolchain/diffie_hellman.rb +10 -0
  38. data/lib/crypto_toolchain/extensions/integer_extensions.rb +90 -0
  39. data/lib/crypto_toolchain/extensions/object_extensions.rb +24 -0
  40. data/lib/crypto_toolchain/extensions/string_extensions.rb +263 -0
  41. data/lib/crypto_toolchain/extensions.rb +8 -0
  42. data/lib/crypto_toolchain/srp/client.rb +51 -0
  43. data/lib/crypto_toolchain/srp/framework.rb +55 -0
  44. data/lib/crypto_toolchain/srp/server.rb +38 -0
  45. data/lib/crypto_toolchain/srp/simple_client.rb +32 -0
  46. data/lib/crypto_toolchain/srp/simple_server.rb +68 -0
  47. data/lib/crypto_toolchain/srp.rb +14 -0
  48. data/lib/crypto_toolchain/tools/aes_ctr_recoverer.rb +30 -0
  49. data/lib/crypto_toolchain/tools/cbc_bitflip_attack.rb +30 -0
  50. data/lib/crypto_toolchain/tools/cbc_iv_equals_key_attack.rb +30 -0
  51. data/lib/crypto_toolchain/tools/cbc_padding_oracle_attack.rb +51 -0
  52. data/lib/crypto_toolchain/tools/ctr_bitflip_attack.rb +24 -0
  53. data/lib/crypto_toolchain/tools/determine_blocksize.rb +20 -0
  54. data/lib/crypto_toolchain/tools/dsa_recover_nonce_from_signatures.rb +53 -0
  55. data/lib/crypto_toolchain/tools/dsa_recover_private_key_from_nonce.rb +39 -0
  56. data/lib/crypto_toolchain/tools/ecb_cut_and_paste_attack.rb +47 -0
  57. data/lib/crypto_toolchain/tools/ecb_interpolate_chosen_plaintext_attack.rb +72 -0
  58. data/lib/crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack.rb +42 -0
  59. data/lib/crypto_toolchain/tools/interactive_xor.rb +51 -0
  60. data/lib/crypto_toolchain/tools/low_exponent_rsa_signature_forgery.rb +27 -0
  61. data/lib/crypto_toolchain/tools/md4_length_extension_attack.rb +30 -0
  62. data/lib/crypto_toolchain/tools/mt_19937_seed_recoverer.rb +27 -0
  63. data/lib/crypto_toolchain/tools/mt_19937_stream_cipher_seed_recoverer.rb +40 -0
  64. data/lib/crypto_toolchain/tools/rsa_broadcast_attack.rb +21 -0
  65. data/lib/crypto_toolchain/tools/rsa_parity_oracle_attack.rb +33 -0
  66. data/lib/crypto_toolchain/tools/rsa_unpadded_message_recovery_attack.rb +49 -0
  67. data/lib/crypto_toolchain/tools/sha1_length_extension_attack.rb +30 -0
  68. data/lib/crypto_toolchain/tools.rb +31 -0
  69. data/lib/crypto_toolchain/utilities/hmac.rb +73 -0
  70. data/lib/crypto_toolchain/utilities/md4.rb +106 -0
  71. data/lib/crypto_toolchain/utilities/mt_19937.rb +218 -0
  72. data/lib/crypto_toolchain/utilities/sha1.rb +95 -0
  73. data/lib/crypto_toolchain/utilities.rb +9 -0
  74. data/lib/crypto_toolchain/version.rb +3 -0
  75. data/lib/crypto_toolchain.rb +34 -0
  76. metadata +232 -0
@@ -0,0 +1,24 @@
1
+ # encoding; ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class CtrBitflipAttack
5
+ def initialize(target: CryptoToolchain::BlackBoxes::CtrBitflipTarget.new)
6
+ @target = target
7
+ end
8
+
9
+ def execute
10
+ easy = ":admin<true:" #only need to flip the last bit of bytes at indices 32, 38, 43
11
+ crypted = target.encrypt(easy)
12
+ crypted.
13
+ flip(7, byte_index: 32).
14
+ flip(7, byte_index: 38).
15
+ flip(7, byte_index: 43)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :target
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ module DetermineBlocksize
4
+ def blocksize
5
+ return @blocksize if defined?(@blocksize)
6
+ original_size = oracle.encrypt("A").length
7
+ i = 2
8
+ loop do
9
+ plain = "A" * i
10
+ len = oracle.encrypt(plain).length
11
+ if len != original_size
12
+ @blocksize = len - original_size
13
+ return @blocksize
14
+ end
15
+ i += 1
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,53 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ # Recovers private key from message signatures signed with the same nonce (k)
4
+ # This means that they have the same r values
5
+ class DSARecoverNonceFromSignatures
6
+ class Input
7
+ def initialize(r: , s: , message: )
8
+ @r = r.to_i
9
+ @s = s.to_i
10
+ @message = message
11
+ @hash = CryptoToolchain::Utilities::SHA1.hexdigest(message)
12
+ end
13
+ attr_reader :r, :s, :message, :hash
14
+ end
15
+
16
+ def initialize(inputs, q: DSA_Q)
17
+ @targets = targets_for(inputs)
18
+ validate_targets!
19
+ @q = q
20
+ end
21
+ attr_reader :targets, :q
22
+
23
+ def execute(params: true)
24
+ t1 = targets.first
25
+ t2 = targets.last
26
+ m1 = t1.hash.hex
27
+ m2 = t2.hash.hex
28
+ s1 = t1.s
29
+ s2 = t2.s
30
+ # (a + b) mod n = [(a mod n) + (b mod n)] mod n.
31
+ top = (m1 - m2) % q
32
+ k = top * (s1 - s2).invmod(q)
33
+ # numerator = ((m1 % q) - (m2 % q)) % q
34
+ k
35
+ end
36
+
37
+ def validate_targets!
38
+ r1 = targets.first.r
39
+ targets[1..-1].each do |t|
40
+ raise ArgumentError.new("All r-values must be identical") unless t.r == r1
41
+ end
42
+ end
43
+
44
+ def targets_for(inputs)
45
+ inputs.
46
+ group_by {|inp| inp.r }.
47
+ select {|k, v| v.length > 1 }.
48
+ values.
49
+ first
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class DSARecoverPrivateKeyFromNonce
4
+ def initialize(public_key: , message: , r: , s: , p: DSA_P, q: DSA_Q, g: DSA_G)
5
+ @public_key = numberize(public_key)
6
+ @p = p
7
+ @q = q
8
+ @g = g
9
+ @r = numberize(r)
10
+ @s = numberize(s)
11
+ @message = message
12
+ end
13
+
14
+ attr_reader :public_key, :message, :r, :s, :p, :q, :g
15
+
16
+ def valid_k?(k)
17
+ x = private_key_from(k: k)
18
+ kp = CryptoToolchain::BlackBoxes::DSAKeypair.new(p: p, q: q, g: g, private_key: x)
19
+ kp.public_key == public_key
20
+ end
21
+
22
+ def private_key_from(k: )
23
+ # (s * k) - H(msg)
24
+ # x = ---------------- mod q
25
+ # r
26
+ numerator = ((s * k) - CryptoToolchain::Utilities::SHA1.digest(message).to_number) % q
27
+ denominator = r.invmod(q)
28
+ ((numerator * denominator) % q).to_bin_string
29
+ end
30
+
31
+ def execute(min: 1, max: 0xffffffff)
32
+ (min..max).each do |k|
33
+ return private_key_from(k: k) if valid_k?(k)
34
+ end
35
+ raise RuntimeError.new("Could not recover key")
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class EcbCutAndPasteAttack
4
+ include DetermineBlocksize
5
+ def initialize(replace: "user",
6
+ with: "admin",
7
+ oracle: CryptoToolchain::BlackBoxes::EcbCutAndPasteTarget.new,
8
+ initial: "charlesisagood@dog.com"
9
+ )
10
+ @oracle = oracle
11
+ @replace = replace
12
+ @replacement = with
13
+ @initial = initial
14
+ end
15
+
16
+ def execute
17
+ without_text_to_change + replaced_text_only
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :oracle, :replace, :replacement, :initial
23
+
24
+ def without_text_to_change
25
+ (0...Float::INFINITY).each do |i|
26
+ input = initial + "X" * i
27
+ oracle.profile_for(input).in_blocks(blocksize).each do |block|
28
+ if block.start_with?(replace)
29
+ return oracle.encrypt(input).in_blocks(blocksize)[0..-2].join
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def replaced_text_only
36
+ (0...Float::INFINITY).each do |i|
37
+ input = initial + "X" * i + replacement
38
+ oracle.profile_for(input).in_blocks(blocksize).each_with_index do |block, bi|
39
+ if block.start_with?(replacement)
40
+ return oracle.encrypt(input).in_blocks(blocksize)[bi]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class EcbInterpolateChosenPlaintextAttack
5
+ include DetermineBlocksize
6
+ PAD = "A".freeze
7
+
8
+ # oracle must return an encrypted string via #encrypt
9
+ def initialize(oracle: CryptoToolchain::BlackBoxes::EcbInterpolateChosenPlaintextOracle.new)
10
+ @oracle = oracle
11
+ unless oracle.encrypt(PAD * blocksize * 10).is_ecb_encrypted?(@blocksize)
12
+ raise ArgumentError.new("Oracle does not appear to encrypt with ECB")
13
+ end
14
+ end
15
+
16
+ def execute
17
+ (0..Float::INFINITY).each_with_object("") do |block_index, solved|
18
+ from_block = (0...blocksize).each_with_object("") do |i, solved_in_block|
19
+ padding_length = blocksize - (solved_in_block.bytes.length) - 1
20
+ padding = PAD * padding_length
21
+ target = oracle_encrypt(padding).in_blocks(blocksize)[block_index + prefix_offset]
22
+ dict = (0..255).map(&:chr).each_with_object({}) do |chr, memo|
23
+ guess = padding + solved + solved_in_block + chr
24
+ output = oracle_encrypt(guess).in_blocks(blocksize)[block_index + prefix_offset]
25
+ memo[output] = chr
26
+ break(memo) if output == target
27
+ end
28
+ if !dict.has_key?(target)
29
+ return "#{solved}#{solved_in_block}"
30
+ end
31
+ solved_in_block << dict.fetch(target)
32
+ end
33
+ solved << from_block
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :oracle
40
+
41
+ def oracle_encrypt(str)
42
+ oracle.encrypt(PAD * prefix_padding_length + str)
43
+ end
44
+
45
+ def prefix_offset
46
+ @prefix_offset ||= large_padding.index(first_repeated_block)
47
+ end
48
+
49
+ def large_padding(large_pad_size = 1024)
50
+ @large_padding ||= oracle.encrypt(PAD * large_pad_size).in_blocks(blocksize)
51
+ end
52
+
53
+ def first_repeated_block
54
+ @first_repeated_block ||= large_padding.
55
+ group_by(&:itself).
56
+ sort_by {|k, v| v.length }.
57
+ last.
58
+ first
59
+ end
60
+
61
+ def prefix_padding_length
62
+ return @prefix_padding_length if defined?(@prefix_padding_length)
63
+ (0..Float::INFINITY).each do |i|
64
+ if oracle.encrypt(PAD * i).in_blocks(blocksize).include?(first_repeated_block)
65
+ @prefix_padding_length = i - blocksize
66
+ return @prefix_padding_length
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class EcbPrependChosenPlaintextAttack
5
+ include DetermineBlocksize
6
+ PAD = "A".freeze
7
+
8
+ # oracle must return an encrypted string via #encrypt
9
+ def initialize(oracle: CryptoToolchain::BlackBoxes::EcbPrependChosenPlaintextOracle.new)
10
+ @oracle = oracle
11
+ unless oracle.encrypt(PAD * blocksize * 10).is_ecb_encrypted?(@blocksize)
12
+ raise ArgumentError.new("Oracle does not appear to encrypt with ECB")
13
+ end
14
+ end
15
+
16
+ def execute
17
+ (0..Float::INFINITY).each_with_object("") do |block_index, solved|
18
+ from_block = (0...blocksize).each_with_object("") do |i, solved_in_block|
19
+ padding_length = blocksize - (solved_in_block.bytes.length) - 1
20
+ padding = PAD * padding_length
21
+ target = oracle.encrypt(padding).in_blocks(blocksize)[block_index]
22
+ dict = (0..255).map(&:chr).each_with_object({}) do |chr, memo|
23
+ guess = padding + solved + solved_in_block + chr
24
+ output = oracle.encrypt(guess).in_blocks(blocksize)[block_index]
25
+ memo[output] = chr
26
+ break(memo) if output == target
27
+ end
28
+ if !dict.has_key?(target)
29
+ return "#{solved}#{solved_in_block}"
30
+ end
31
+ solved_in_block << dict.fetch(target)
32
+ end
33
+ solved << from_block
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :oracle
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ #encoding ASCII-8BIT
2
+ #
3
+ # nonce = 0
4
+ # key = "a'\xC2[R\xEE\x8F2K\xBA\xCA\x980\x9Bb\xD5"
5
+ # _plains = File.read("spec/fixtures/3-19.txt").split("\n").map(&:strip).map(&:from_base64)
6
+ # ciphertexts = _plains.map {|pl| pl.encrypt_ctr(key: key, nonce: nonce, blocksize: 16)}
7
+ # CryptoToolchain::Tools::InteractiveXor.new(ciphertexts).execute
8
+ #
9
+ module CryptoToolchain
10
+ module Tools
11
+ class InteractiveXor
12
+ attr_reader :ciphertexts
13
+ def initialize(ciphertexts)
14
+ @ciphertexts = ciphertexts
15
+ end
16
+
17
+ def execute
18
+ binding.pry
19
+ end
20
+
21
+ def validate_length!(plains)
22
+ len = plains.first.length
23
+ plains.each do |pl|
24
+ raise ArgumentError.new("must have same length") unless pl.length == len
25
+ end
26
+ end
27
+
28
+ def keys_for(plains, index)
29
+ plains.map.with_index do |pl|
30
+ len = [pl.length, ciphertexts[index].length].min
31
+ ciphertexts[index][0...len] ^ pl[0...len]
32
+ end
33
+ end
34
+
35
+ # index is the index of the ciphertext against which you are making an attempt
36
+ # Plains are the plaintexts you want to try as possibilities
37
+ def attempt(index, *plains)
38
+ validate_length!(plains)
39
+ keys = keys_for(plains, index)
40
+ ciphertexts.each_with_index do |ct, i|
41
+ line = keys.map do |k|
42
+ _len = [ct.bytesize, k.bytesize].min
43
+ ct[0..._len] ^ k[0..._len]
44
+ end.join(" | ")
45
+ puts "#{i}\t#{line}"
46
+ end
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class LowExponentRSASignatureForgery
5
+ def initialize(message: , keypair: )
6
+ @keypair = keypair
7
+ @message = message
8
+ end
9
+ attr_reader :keypair, :message
10
+
11
+ def execute
12
+ digest = CryptoToolchain::Utilities::SHA1.digest(message)
13
+ asn = ASN1.fetch(:sha1)
14
+ max = (keypair.bits / 8) - (asn.bytesize + digest.bytesize + 3)
15
+ (1..max).reverse_each do |padlen|
16
+ forged = "\x01\xff\x00#{asn}#{digest}#{0.chr * padlen}".
17
+ to_number.
18
+ root(3, round: :up).
19
+ to_bin_string
20
+ found = keypair.verify(message, signature: forged)
21
+ return forged if found
22
+ end
23
+ raise RuntimeError.new("Couldn't forge a signature")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class MD4LengthExtensionAttack
5
+ def initialize(message: , add: , mac: , key_length: )
6
+ @message = message
7
+ @mac = mac
8
+ @add = add
9
+ @key_length = key_length
10
+ end
11
+
12
+ # @return Array [msg, digest] Message that can be validated
13
+ def execute
14
+ dummy_key = "A" * key_length
15
+ padding = CryptoToolchain::Utilities::MD4.padding(dummy_key + message)
16
+ [
17
+ message + padding + add,
18
+ CryptoToolchain::Utilities::MD4.hexdigest(add,
19
+ state: mac,
20
+ append_length: (padding + message + dummy_key).length
21
+ )
22
+ ]
23
+ end
24
+
25
+ attr_reader :message, :mac, :add, :key_length
26
+
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,27 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class MT19937SeedRecoverer
4
+ def initialize(extracted, start: default_start, finish: Time.now.to_i)
5
+ @extracted = extracted
6
+ @start = start
7
+ @finish = finish
8
+ end
9
+
10
+ def execute
11
+ (start..finish).each do |seed|
12
+ if CryptoToolchain::Utilities::MT19937.new(seed).extract == extracted
13
+ return seed
14
+ end
15
+ end
16
+ raise RuntimeError, "Did not find the seed; consider expanding start and finish"
17
+ end
18
+
19
+ attr_reader :extracted, :start, :finish
20
+
21
+ # One hour ago
22
+ def default_start
23
+ Time.now.to_i - (3600)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class MT19937StreamCipherSeedRecoverer
4
+ class << self
5
+ def recover_from(ciphertext: , seed: )
6
+ stream = CryptoToolchain::BlackBoxes::MT19937StreamCipher.new(ciphertext, seed: seed)
7
+ stream.decrypt(ciphertext)
8
+ end
9
+
10
+ def valid_token?(tok, start: Time.now.to_i - 5, finish: Time.now.to_i)
11
+ (start..finish).each do |seed|
12
+ if tok == CryptoToolchain::BlackBoxes::MT19937StreamCipher.generate_token(seed: seed)
13
+ return true
14
+ end
15
+ end
16
+ false
17
+ end
18
+ alias_method :valid_token, :valid_token?
19
+ end
20
+
21
+ def initialize(ciphertext: , known: )
22
+ @ciphertext = ciphertext
23
+ @known = known
24
+ end
25
+
26
+ def execute
27
+ (0..CryptoToolchain::BlackBoxes::MT19937StreamCipher::MAX_SEED).each do |seed|
28
+ cipher = CryptoToolchain::BlackBoxes::MT19937StreamCipher.new(ciphertext, seed: seed)
29
+ if cipher.decrypt(ciphertext).include?(known)
30
+ return seed
31
+ end
32
+ end
33
+ raise RuntimeError.new, "Could not recover seed"
34
+ end
35
+
36
+ attr_reader :known, :ciphertext
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class RSABroadcastAttack
4
+ Input = Struct.new(:ciphertext, :public_key)
5
+ def initialize(inputs)
6
+ @e = inputs.length
7
+ @inputs = inputs
8
+ end
9
+ attr_reader :inputs, :e
10
+
11
+ def execute
12
+ residues = inputs.map(&:ciphertext)
13
+ mods = inputs.map {|i| i.public_key.n }
14
+ result = chinese_remainder(residues, mods)
15
+ result.root(e).
16
+ to_s(16).
17
+ from_hex
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class RSAParityOracleAttack
4
+ def initialize(oracle: , n: , e: 3)
5
+ @oracle = oracle
6
+ @n = n
7
+ @e = e
8
+ end
9
+ attr_reader :n, :oracle, :e
10
+
11
+ def execute(_ciphertext, output: false)
12
+ ciphertext = _ciphertext.to_number
13
+ min = BigDecimal(0)
14
+ max = BigDecimal(n)
15
+ mid = max/2
16
+ mult = 2.modpow(e, n)
17
+ Math.log2(n).ceil.times do
18
+ mid = (min + max) / 2
19
+ ciphertext = ((ciphertext) * mult) % n
20
+ if oracle.execute(ciphertext.to_bin_string) == 0
21
+ max = mid
22
+ else
23
+ min = mid
24
+ end
25
+ if output
26
+ print "\e[2J\e[f\r#{max.to_i.to_bin_string.gsub(/[^[:print:]]/, '*')}"
27
+ end
28
+ end
29
+ max.to_i.to_bin_string
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,49 @@
1
+ module CryptoToolchain
2
+ module Tools
3
+ class RSAUnpaddedMessageRecoveryAttack
4
+
5
+ attr_reader :oracle, :s
6
+
7
+ def initialize(oracle: , s: 2)
8
+ @oracle = oracle
9
+ @s = s
10
+ end
11
+
12
+ def execute(ciphertext)
13
+ plaintext(
14
+ p_prime(
15
+ c_prime(
16
+ ciphertext.to_number
17
+ )
18
+ )
19
+ )
20
+ end
21
+
22
+ private
23
+
24
+ def e
25
+ oracle.keypair.e
26
+ end
27
+
28
+ def n
29
+ oracle.keypair.public_key.n
30
+ end
31
+
32
+ def c_prime(c)
33
+ (s.modpow(e, n) * c) % n
34
+ end
35
+
36
+ def p_prime(_c_prime)
37
+ oracle.execute(
38
+ _c_prime.to_bin_string
39
+ ).to_number
40
+ end
41
+
42
+ def plaintext(_p_prime)
43
+ (
44
+ (_p_prime * s.invmod(n)) % n
45
+ ).to_bin_string
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class SHA1LengthExtensionAttack
5
+ def initialize(message: , add: , mac: , key_length: )
6
+ @message = message
7
+ @mac = mac
8
+ @add = add
9
+ @key_length = key_length
10
+ end
11
+
12
+ # @return Array [msg, digest] Message that can be validated
13
+ def execute
14
+ dummy_key = "A" * key_length
15
+ padding = CryptoToolchain::Utilities::SHA1.padding(dummy_key + message)
16
+ [
17
+ message + padding + add,
18
+ CryptoToolchain::Utilities::SHA1.hexdigest(add,
19
+ state: mac,
20
+ append_length: (padding + message + dummy_key).length
21
+ )
22
+ ]
23
+ end
24
+
25
+ attr_reader :message, :mac, :add, :key_length
26
+
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,31 @@
1
+ require "crypto_toolchain/tools/determine_blocksize"
2
+ require "crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack"
3
+ require "crypto_toolchain/tools/ecb_interpolate_chosen_plaintext_attack"
4
+ require "crypto_toolchain/tools/ecb_cut_and_paste_attack"
5
+ require "crypto_toolchain/tools/cbc_bitflip_attack"
6
+ require "crypto_toolchain/tools/cbc_padding_oracle_attack"
7
+ require "crypto_toolchain/tools/interactive_xor"
8
+ require "crypto_toolchain/tools/mt_19937_seed_recoverer"
9
+ require "crypto_toolchain/tools/mt_19937_stream_cipher_seed_recoverer"
10
+ require "crypto_toolchain/tools/aes_ctr_recoverer"
11
+ require "crypto_toolchain/tools/ctr_bitflip_attack"
12
+ require "crypto_toolchain/tools/cbc_iv_equals_key_attack"
13
+ require "crypto_toolchain/tools/sha1_length_extension_attack"
14
+ require "crypto_toolchain/tools/md4_length_extension_attack"
15
+ require "crypto_toolchain/tools/rsa_broadcast_attack"
16
+ require "crypto_toolchain/tools/rsa_unpadded_message_recovery_attack"
17
+ require "crypto_toolchain/tools/low_exponent_rsa_signature_forgery"
18
+ require "crypto_toolchain/tools/dsa_recover_private_key_from_nonce"
19
+ require "crypto_toolchain/tools/dsa_recover_nonce_from_signatures"
20
+ require "crypto_toolchain/tools/rsa_parity_oracle_attack"
21
+
22
+ module CryptoToolchain
23
+ module Tools
24
+ def self.detect_single_character_xor(bytestring, non_printable: true)
25
+ arr = non_printable ? (0..255).map(&:chr).to_a : CryptoToolchain::PRINTABLE_CHARACTERS
26
+ arr.sort_by do |chr|
27
+ (chr.repeat_to(bytestring.length) ^ bytestring).score
28
+ end.last
29
+ end
30
+ end
31
+ end