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 +5 -5
- data/.gitignore +2 -0
- data/.travis.yml +1 -0
- data/README.md +6 -2
- data/lib/crypto_toolchain/black_boxes/rsa_keypair.rb +22 -9
- data/lib/crypto_toolchain/black_boxes/rsa_padding_oracle.rb +17 -0
- data/lib/crypto_toolchain/black_boxes.rb +1 -0
- data/lib/crypto_toolchain/extensions/integer_extensions.rb +9 -0
- data/lib/crypto_toolchain/extensions/string_extensions.rb +14 -3
- data/lib/crypto_toolchain/tools/rsa_padding_oracle_attack.rb +124 -0
- data/lib/crypto_toolchain/tools.rb +1 -0
- data/lib/crypto_toolchain/version.rb +1 -1
- data/lib/crypto_toolchain.rb +1 -0
- metadata +5 -4
- data/.rspec +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: abf3eb1ea6db35f164ee955e811d817ce4a54ce5f8dbfb7c26622662fe15b7ac
|
4
|
+
data.tar.gz: f65fe236e0594960033508c94570cb147fbda144db077570e946e0733282e062
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7db6ff7adb0b11efd29a5fd987f71e1517d6be8509007f4092bcef3e74076c907ef6f59a3b3f98b84b589563611a85882d89a12cee7ed4c30d972753c5457f5e
|
7
|
+
data.tar.gz: a1632d18cab50cc48228ce4394f3edefc923eb7e692ba213ad9acce2ab0d3a7a7d91127f9dcb7168ae3fc279ac6eba47c4798dd77bdd9a58fdc3f73a48871718
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
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
|
-
* [
|
75
|
-
* [
|
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
|
-
|
32
|
-
|
33
|
-
|
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
|
@@ -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
|
-
|
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
|
data/lib/crypto_toolchain.rb
CHANGED
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.
|
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:
|
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
|
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