crypto_toolchain 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 85833999c67482bc9ca5ef223a039b9a82c3675b
4
- data.tar.gz: e1ab0345bc0a089458206def1cc30e47fb94bdd0
2
+ SHA256:
3
+ metadata.gz: abf3eb1ea6db35f164ee955e811d817ce4a54ce5f8dbfb7c26622662fe15b7ac
4
+ data.tar.gz: f65fe236e0594960033508c94570cb147fbda144db077570e946e0733282e062
5
5
  SHA512:
6
- metadata.gz: 180ebe2b0b30fb9666b2b0d1ad92ec0b6be2b124a6bdf70e7a3f7977e286e2c3479eca677d5fb2af99ae4569812da6201a836cf85f3c4e25cd8a9fe248a5db1d
7
- data.tar.gz: 5075be9cac22c796664b0318287f37ff48cf22af86216d2ca70c5c0a5a7a8d165e6b888a1008a010139319b1f61784a884245a559d618d4f6def1b405f32b0be
6
+ metadata.gz: 7db6ff7adb0b11efd29a5fd987f71e1517d6be8509007f4092bcef3e74076c907ef6f59a3b3f98b84b589563611a85882d89a12cee7ed4c30d972753c5457f5e
7
+ data.tar.gz: a1632d18cab50cc48228ce4394f3edefc923eb7e692ba213ad9acce2ab0d3a7a7d91127f9dcb7168ae3fc279ac6eba47c4798dd77bdd9a58fdc3f73a48871718
data/.gitignore CHANGED
@@ -10,6 +10,8 @@
10
10
  /test/version_tmp/
11
11
  /tmp/
12
12
  Gemfile.lock
13
+ .ruby-version
14
+ .rspec
13
15
 
14
16
  # Used by dotenv library to load environment variables.
15
17
  # .env
data/.travis.yml CHANGED
@@ -3,3 +3,4 @@ language: ruby
3
3
  rvm:
4
4
  - 2.3.3
5
5
  before_install: gem install bundler -v 1.13.6
6
+ script: travis_wait bundle exec rspec
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/ffleming/crypto_toolchain.svg?branch=master)](https://travis-ci.org/ffleming/crypto_toolchain)
2
+
1
3
  # CryptoToolchain
2
4
 
3
5
  This is a suite of tools for ruining the blue team's day with respect to crypto.
@@ -8,6 +10,8 @@ cryptographic vulnerabilities.
8
10
 
9
11
  NB: These will probably never be finished
10
12
 
13
+ Add `--tag ~slow` to your `.rspec` file if you don't want to run slow tests.
14
+
11
15
  ## Cryptopals progress
12
16
 
13
17
  ### Set 1: Basics
@@ -71,8 +75,8 @@ NB: These will probably never be finished
71
75
  * [x] DSA nonce recovery from repeated nonce
72
76
  * [x] DSA parameter tampering
73
77
  * [x] RSA parity oracle
74
- * [ ] Bleichenbacher's PKCS 1.5 Padding Oracle (Simple Case)
75
- * [ ] Bleichenbacher's PKCS 1.5 Padding Oracle (Complete Case)
78
+ * [x] Bleichenbacher's PKCS 1.5 Padding Oracle (Simple Case)
79
+ * [x] Bleichenbacher's PKCS 1.5 Padding Oracle (Complete Case)
76
80
 
77
81
  ### Set 7: Hashes
78
82
  * [ ] CBC-MAC Message Forgery
@@ -5,17 +5,17 @@ module CryptoToolchain
5
5
  PrivateKey = Struct.new(:d, :n)
6
6
  PublicKey = Struct.new(:e, :n)
7
7
 
8
- def initialize(bits: 1024)
8
+ def initialize(bits: 1024, p: nil, q: nil)
9
9
  @bits = bits
10
- @p = OpenSSL::BN::generate_prime(bits/2).to_i
11
- @q = OpenSSL::BN::generate_prime(bits/2).to_i
10
+ @p = p || OpenSSL::BN::generate_prime(bits/2).to_i
11
+ @q = q || OpenSSL::BN::generate_prime(bits/2).to_i
12
12
  @n = @p * @q
13
13
  et = (@p-1) * (@q-1)
14
14
  @e = 3
15
15
  @d = @e.invmod(et)
16
16
  end
17
17
 
18
- attr_reader :e, :bits
18
+ attr_reader :e, :bits, :p, :q
19
19
 
20
20
  def encrypt(m, to: )
21
21
  raise ArgumentError.new("Message should be a string") unless m.is_a?(String)
@@ -25,12 +25,17 @@ module CryptoToolchain
25
25
  to_bin_string
26
26
  end
27
27
 
28
- def decrypt(m)
28
+ def decrypt(m, pad: false)
29
29
  raise ArgumentError.new("Message should be a string") unless m.is_a?(String)
30
- m.
31
- to_number.
32
- modpow(private_key.d, private_key.n).
33
- to_bin_string
30
+ decrypted = m.
31
+ to_number.
32
+ modpow(private_key.d, private_key.n).
33
+ to_bin_string
34
+ if pad
35
+ pad_to_key_size(decrypted)
36
+ else
37
+ decrypted
38
+ end
34
39
  end
35
40
 
36
41
  def sign(plaintext)
@@ -78,6 +83,14 @@ module CryptoToolchain
78
83
  sha512: "0Q0\r\x06\t`\x86H\x01e\x03\x04\x02\x03\x05\x00\x04@"
79
84
  }.fetch(hash_type)
80
85
  end
86
+
87
+ def pad_to_key_size(str)
88
+ padded = str.dup
89
+ while padded.bytesize < bits / 8
90
+ padded = "\x00#{padded}"
91
+ end
92
+ padded
93
+ end
81
94
  end
82
95
  end
83
96
  end
@@ -0,0 +1,17 @@
1
+ module CryptoToolchain
2
+ module BlackBoxes
3
+ class RSAPaddingOracle
4
+ def initialize(keypair: CryptoToolchain::BlackBoxes::RSAKeypair.new(bits: 256))
5
+ @keypair = keypair
6
+ end
7
+
8
+ attr_reader :keypair
9
+
10
+ def execute(str)
11
+ keypair.
12
+ decrypt(str, pad: true).
13
+ is_pkcs1_5_padded?(keypair.bits)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -15,6 +15,7 @@ require "crypto_toolchain/black_boxes/rsa_keypair"
15
15
  require "crypto_toolchain/black_boxes/rsa_unpadded_message_recovery_oracle"
16
16
  require "crypto_toolchain/black_boxes/rsa_parity_oracle"
17
17
  require "crypto_toolchain/black_boxes/dsa_keypair"
18
+ require "crypto_toolchain/black_boxes/rsa_padding_oracle"
18
19
 
19
20
  module CryptoToolchain
20
21
  module BlackBoxes
@@ -87,4 +87,13 @@ class Integer
87
87
  product
88
88
  end
89
89
  alias_method :modpow, :modexp
90
+
91
+ def updiv(other)
92
+ quot, remainder = self.divmod(other)
93
+ if remainder == 0
94
+ quot
95
+ else
96
+ quot + 1
97
+ end
98
+ end
90
99
  end
@@ -123,10 +123,21 @@ class String
123
123
  end
124
124
  end
125
125
 
126
+ def pad_pkcs1_5(bits)
127
+ len = bits / 8
128
+ if self.bytesize > len - 11
129
+ raise ArgumentError.new("String #{self.inspect} is too long to pad with PKCS#1v1.5, length: #{self.bytesize}")
130
+ end
131
+ padstring = (len - 3 - self.bytesize).times.with_object("") { |_, memo| memo << rand(1..255).chr }
132
+ "\x00\x02#{padstring}\x00#{self}"
133
+ end
134
+
135
+ def is_pkcs1_5_padded?(bits)
136
+ self[0..1] == "\x00\x02"
137
+ end
138
+
126
139
  def is_pkcs7_padded?(blocksize = CryptoToolchain::AES_BLOCK_SIZE)
127
- # if self.size != blocksize
128
- return in_blocks(blocksize).last.is_block_pkcs7_padded?(blocksize)
129
- # end
140
+ return in_blocks(blocksize).last.is_block_pkcs7_padded?(blocksize)
130
141
  end
131
142
 
132
143
  def without_pkcs7_padding(blocksize = CryptoToolchain::AES_BLOCK_SIZE, raise_error: false)
@@ -0,0 +1,124 @@
1
+ # encoding: ASCII-8BIT
2
+ module CryptoToolchain
3
+ module Tools
4
+ class RSAPaddingOracleAttack
5
+ end
6
+ end
7
+ end
8
+
9
+ class CryptoToolchain::Tools::RSAPaddingOracleAttack
10
+ def initialize(oracle: BlackBoxes::RSAPaddingOracle.new, n: , e: 3)
11
+ @oracle = oracle
12
+ @n = n
13
+ @e = e
14
+ end
15
+ attr_reader :n, :oracle, :e
16
+
17
+ def check(int)
18
+ oracle.execute(str_for(int))
19
+ end
20
+
21
+ def str_for(int)
22
+ str = int.to_bin_string
23
+ pad = "\x00" * (n.bit_length.updiv(8) - str.bytesize)
24
+ "#{pad}#{str}"
25
+ end
26
+
27
+ def execute(ciphertext)
28
+ s = 1
29
+ @c0 = ciphertext.to_number
30
+ intervals = [ [ (2*big_b), (3*big_b ) ] ]
31
+ i = 1
32
+ loop do
33
+ if i == 1
34
+ #2a
35
+ s = start_search()
36
+ elsif intervals.length > 1
37
+ #2b
38
+ s += 1
39
+ s += 1 until check((@c0 * s.modpow(e, n)) % n)
40
+ elsif intervals.length == 1
41
+ #2c
42
+ a, b = intervals.first
43
+
44
+ if a == b
45
+ return str_for(a)
46
+ end
47
+ s = search_with_single_interval(a, b, s)
48
+ end
49
+
50
+ # 3
51
+ intervals = calculate_intervals(intervals, s)
52
+ i += 1
53
+ end
54
+ end
55
+
56
+
57
+ def calculate_intervals(intervals, s)
58
+ new_intervals = []
59
+ intervals.each do |a, b|
60
+ min_r = (a * s - 3 * big_b + 1).updiv(n)
61
+ max_r = (b * s - 2 * big_b) / n
62
+ (min_r..max_r).each do |r|
63
+ aa = [a, (2 * big_b + r * n).updiv(s)].max
64
+ bb = [b, ((3 * big_b - 1 + r * n) / s)].min
65
+
66
+ new_intervals = add_interval(new_intervals, aa, bb)
67
+ end
68
+ end
69
+ new_intervals
70
+ end
71
+
72
+ def add_interval(intervals, lower, upper)
73
+ matched = false
74
+ new_intervals = intervals.map do |a, b|
75
+ if b < lower || a > upper
76
+ # interval to be added does not overlap an existing interval - persist the existing interval
77
+ # if we never overlap an interval, we'll add the [lower, upper] interval later
78
+ [a, b]
79
+ else
80
+ # interval to be added overlaps - extend that interval according to [lower, upper]
81
+ matched = true
82
+ [
83
+ [lower, a].min,
84
+ [upper, b].max
85
+ ]
86
+ end
87
+ end
88
+ if matched
89
+ new_intervals
90
+ else
91
+ new_intervals.push([lower, upper])
92
+ end
93
+ end
94
+
95
+ def start_search
96
+ s1 = n.updiv(3 * big_b)
97
+ loop do
98
+ c = (@c0 * s1.modpow(e, n)) % n
99
+ if check(c)
100
+ return s1
101
+ end
102
+ s1 += 1
103
+ end
104
+ end
105
+
106
+ def search_with_single_interval(a, b, s)
107
+ r = (2 * (b * s - 2 * big_b)) / (n)
108
+ s = (2 * big_b + r * n) / (b)
109
+
110
+ until check((@c0 * s.modpow(e,n)) % n)
111
+ s += 1
112
+ if s > (3 * big_b + r * n) / a
113
+ r += 1
114
+ s = (2 * big_b + r * n) / b
115
+ end
116
+ end
117
+ s
118
+ end
119
+
120
+ def big_b
121
+ k = oracle.keypair.bits / 8
122
+ 2**(8 * (k - 2))
123
+ end
124
+ end
@@ -18,6 +18,7 @@ require "crypto_toolchain/tools/low_exponent_rsa_signature_forgery"
18
18
  require "crypto_toolchain/tools/dsa_recover_private_key_from_nonce"
19
19
  require "crypto_toolchain/tools/dsa_recover_nonce_from_signatures"
20
20
  require "crypto_toolchain/tools/rsa_parity_oracle_attack"
21
+ require "crypto_toolchain/tools/rsa_padding_oracle_attack"
21
22
 
22
23
  module CryptoToolchain
23
24
  module Tools
@@ -1,3 +1,3 @@
1
1
  module CryptoToolchain
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -7,6 +7,7 @@ require "uri"
7
7
  require 'json'
8
8
  require 'securerandom'
9
9
  require "bigdecimal"
10
+ require 'openssl'
10
11
  require "crypto_toolchain/version"
11
12
  require "crypto_toolchain/extensions"
12
13
  require "crypto_toolchain/utilities"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crypto_toolchain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Forrest Fleming
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-09 00:00:00.000000000 Z
11
+ date: 2018-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry-byebug
@@ -132,7 +132,6 @@ extensions: []
132
132
  extra_rdoc_files: []
133
133
  files:
134
134
  - ".gitignore"
135
- - ".rspec"
136
135
  - ".travis.yml"
137
136
  - Gemfile
138
137
  - Guardfile
@@ -159,6 +158,7 @@ files:
159
158
  - lib/crypto_toolchain/black_boxes/mt_19937_stream_cipher.rb
160
159
  - lib/crypto_toolchain/black_boxes/netcat_cbc_padding_oracle.rb
161
160
  - lib/crypto_toolchain/black_boxes/rsa_keypair.rb
161
+ - lib/crypto_toolchain/black_boxes/rsa_padding_oracle.rb
162
162
  - lib/crypto_toolchain/black_boxes/rsa_parity_oracle.rb
163
163
  - lib/crypto_toolchain/black_boxes/rsa_unpadded_message_recovery_oracle.rb
164
164
  - lib/crypto_toolchain/black_boxes/sha1_mac.rb
@@ -196,6 +196,7 @@ files:
196
196
  - lib/crypto_toolchain/tools/mt_19937_seed_recoverer.rb
197
197
  - lib/crypto_toolchain/tools/mt_19937_stream_cipher_seed_recoverer.rb
198
198
  - lib/crypto_toolchain/tools/rsa_broadcast_attack.rb
199
+ - lib/crypto_toolchain/tools/rsa_padding_oracle_attack.rb
199
200
  - lib/crypto_toolchain/tools/rsa_parity_oracle_attack.rb
200
201
  - lib/crypto_toolchain/tools/rsa_unpadded_message_recovery_attack.rb
201
202
  - lib/crypto_toolchain/tools/sha1_length_extension_attack.rb
@@ -225,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
226
  version: '0'
226
227
  requirements: []
227
228
  rubyforge_project:
228
- rubygems_version: 2.6.11
229
+ rubygems_version: 2.7.6
229
230
  signing_key:
230
231
  specification_version: 4
231
232
  summary: Crypto toolchain for CTFs and so on
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color