crypto_toolchain 0.1.1 → 0.2.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 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