crypto_toolchain 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5c925134cae022ff1f352dd99a514ed156af2b24
|
4
|
+
data.tar.gz: 6da3e5de58817cc75ea75cb0463ccb2230dee7b9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0dac92e2f29f7c800a15f0e8af6ef46581b9c23564fd73aa90fd80a90239ee67c59f21b8f94c2b588f8533ff9222ecd868e6b3b7ff3e34beab0b45d35044c274
|
7
|
+
data.tar.gz: ff82e12216383e5732637bc50fd93a34363972b119f2a9d3094a49076abd1737f025d0dfc48bfefba4941b2d88cd185f5a6fcaeff380a8c817221773aad60121
|
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
Gemfile.lock
|
13
|
+
|
14
|
+
# Used by dotenv library to load environment variables.
|
15
|
+
# .env
|
16
|
+
|
17
|
+
## Specific to RubyMotion:
|
18
|
+
.dat*
|
19
|
+
.repl_history
|
20
|
+
build/
|
21
|
+
*.bridgesupport
|
22
|
+
build-iPhoneOS/
|
23
|
+
build-iPhoneSimulator/
|
24
|
+
|
25
|
+
## Specific to RubyMotion (use of CocoaPods):
|
26
|
+
#
|
27
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
28
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
29
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
30
|
+
#
|
31
|
+
# vendor/Pods/
|
32
|
+
|
33
|
+
## Documentation cache and generated files:
|
34
|
+
/.yardoc/
|
35
|
+
/_yardoc/
|
36
|
+
/doc/
|
37
|
+
/rdoc/
|
38
|
+
|
39
|
+
## Environment normalization:
|
40
|
+
/.bundle/
|
41
|
+
/vendor/bundle
|
42
|
+
/lib/bundler/man/
|
43
|
+
|
44
|
+
# for a library or gem, you might want to ignore these files since the code is
|
45
|
+
# intended to run in multiple environments; otherwise, check them in:
|
46
|
+
# Gemfile.lock
|
47
|
+
# .ruby-version
|
48
|
+
# .ruby-gemset
|
49
|
+
|
50
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
51
|
+
.rvmrc
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
2
|
+
require "guard/rspec/dsl"
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
|
5
|
+
# RSpec files
|
6
|
+
rspec = dsl.rspec
|
7
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
8
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
9
|
+
watch(rspec.spec_files)
|
10
|
+
|
11
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
12
|
+
|
13
|
+
ruby = dsl.ruby
|
14
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
15
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Forrest Fleming
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# CryptoToolchain
|
2
|
+
|
3
|
+
This is a suite of tools for ruining the blue team's day with respect to crypto.
|
4
|
+
|
5
|
+
It is mostly based on the Matasano/Cryptopals challenges, because they lead you
|
6
|
+
by the hand down the garden path to breaking a good number of common
|
7
|
+
cryptographic vulnerabilities.
|
8
|
+
|
9
|
+
NB: These will probably never be finished
|
10
|
+
|
11
|
+
## Cryptopals progress
|
12
|
+
|
13
|
+
### Set 1: Basics
|
14
|
+
* [x] Convert hex to base64
|
15
|
+
* [x] Fixed XOR
|
16
|
+
* [x] Single-byte XOR cipher
|
17
|
+
* [x] Detect single-character XOR
|
18
|
+
* [x] Implement repeating-key XOR
|
19
|
+
* [x] Break repeating-key XOR
|
20
|
+
* [x] AES in ECB mode
|
21
|
+
* [x] Detect AES in ECB mode
|
22
|
+
|
23
|
+
### Set 2: Block crypto
|
24
|
+
* [x] Implement PKCS#7 padding
|
25
|
+
* [x] Implement CBC mode
|
26
|
+
* [x] An ECB/CBC detection oracle
|
27
|
+
* [x] Byte-at-a-time ECB decryption (Simple)
|
28
|
+
* [x] ECB cut-and-paste
|
29
|
+
* [x] Byte-at-a-time ECB decryption (Harder)
|
30
|
+
* [x] PKCS#7 padding validation
|
31
|
+
* [x] CBC bitflipping attacks
|
32
|
+
|
33
|
+
### Set 3: Block & stream crypto
|
34
|
+
* [x] The CBC padding oracle
|
35
|
+
* [x] Implement CTR, the stream cipher mode
|
36
|
+
* [x] Break fixed-nonce CTR mode using substitutions
|
37
|
+
* [x] Break fixed-nonce CTR statistically
|
38
|
+
* [x] Implement the MT19937 Mersenne Twister RNG
|
39
|
+
* [x] Crack an MT19937 seed
|
40
|
+
* [x] Clone an MT19937 RNG from its output
|
41
|
+
* [x] Create the MT19937 stream cipher and break it
|
42
|
+
|
43
|
+
### Set 4: Stream crypto & randomness
|
44
|
+
* [x] Break "random access read/write" AES CTR
|
45
|
+
* [x] CTR bitflipping
|
46
|
+
* [x] Recover the key from CBC with IV=Key
|
47
|
+
* [x] Implement a SHA-1 keyed MAC
|
48
|
+
* [x] Break a SHA-1 keyed MAC using length extension
|
49
|
+
* [x] Break an MD4 keyed MAC using length extension
|
50
|
+
* [x] Implement and break HMAC-SHA1 with an artificial timing leak
|
51
|
+
* See [timing_attack](https://github.com/ffleming/timing_attack) for a timing attack tool
|
52
|
+
* See [camelflage](https://github.com/ffleming/camelflage) for the vulnerable server
|
53
|
+
* [x] Break HMAC-SHA1 with a slightly less artificial timing leak
|
54
|
+
* See [timing_attack](https://github.com/ffleming/timing_attack) for a timing attack tool
|
55
|
+
* See [camelflage](https://github.com/ffleming/camelflage) for the vulnerable server
|
56
|
+
|
57
|
+
### Set 5: Diffie-Hellman & friends
|
58
|
+
* [x] Implement Diffie-Hellman
|
59
|
+
* [x] Implement a MITM key-fixing attack on Diffie-Hellman with parameter injection
|
60
|
+
* [x] Implement DH with negotiated groups, and break with malicious "g" parameters
|
61
|
+
* [x] Implement Secure Remote Password (SRP)
|
62
|
+
* [x] Break SRP with a zero key
|
63
|
+
* [x] Offline dictionary attack on simplified SRP
|
64
|
+
* [x] Implement RSA
|
65
|
+
* [x] Implement an E=3 RSA Broadcast attack
|
66
|
+
|
67
|
+
### Set 6: RSA & DSA
|
68
|
+
* [x] Implement unpadded message recovery oracle
|
69
|
+
* [x] Bleichenbacher's e=3 RSA Attack
|
70
|
+
* [x] DSA key recovery from nonce
|
71
|
+
* [x] DSA nonce recovery from repeated nonce
|
72
|
+
* [x] DSA parameter tampering
|
73
|
+
* [x] RSA parity oracle
|
74
|
+
* [ ] Bleichenbacher's PKCS 1.5 Padding Oracle (Simple Case)
|
75
|
+
* [ ] Bleichenbacher's PKCS 1.5 Padding Oracle (Complete Case)
|
76
|
+
|
77
|
+
### Set 7: Hashes
|
78
|
+
* [ ] CBC-MAC Message Forgery
|
79
|
+
* [ ] Hashing with CBC-MAC
|
80
|
+
* [ ] Compression Ratio Side-Channel Attacks
|
81
|
+
* [ ] Iterated Hash Function Multicollisions
|
82
|
+
* [ ] Kelsey and Schneier's Expandable Messages
|
83
|
+
* [ ] Kelsey and Kohno's Nostradamus Attack
|
84
|
+
* [ ] MD4 Collisions
|
85
|
+
* [ ] RC4 Single-Byte Biases
|
86
|
+
|
87
|
+
### Set 8: Abstract Algebra
|
88
|
+
* [ ] Diffie-Hellman Revisited: Small Subgroup Confinement
|
89
|
+
* [ ] Pollard's Method for Catching Kangaroos
|
90
|
+
* [ ] Elliptic Curve Diffie-Hellman and Invalid-Curve Attacks
|
91
|
+
* [ ] Single-Coordinate Ladders and Insecure Twists
|
92
|
+
* [ ] Duplicate-Signature Key Selection in ECDSA (and RSA)
|
93
|
+
* [ ] Key-Recovery Attacks on ECDSA with Biased Nonces
|
94
|
+
* [ ] Key-Recovery Attacks on GCM with Repeated Nonces
|
95
|
+
* [ ] Key-Recovery Attacks on GCM with a Truncated MAC
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "crypto_toolchain"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
12
|
+
|
13
|
+
# require "irb"
|
14
|
+
# IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'crypto_toolchain/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "crypto_toolchain"
|
8
|
+
spec.version = CryptoToolchain::VERSION
|
9
|
+
spec.authors = ["Forrest Fleming"]
|
10
|
+
spec.email = ["ffleming@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "Crypto toolchain for CTFs and so on"
|
13
|
+
spec.description = "A toolchain for manipulating data in a variety of cryptographic " <<
|
14
|
+
"and quasi-cryptographic ways."
|
15
|
+
spec.homepage = "https://github.com/ffleming/crypto_toolchain"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
spec.licenses = ["MIT"]
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "pry-byebug", "3.4"
|
26
|
+
spec.add_runtime_dependency "openssl", "~> 2.0"
|
27
|
+
spec.add_runtime_dependency "bigdecimal", "~> 1.2"
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
29
|
+
spec.add_development_dependency "guard-rspec", "~> 4.7"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
32
|
+
spec.add_development_dependency "simplecov", "~> 0.15"
|
33
|
+
end
|
data/exe/crypto
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module BlackBoxes
|
3
|
+
class AesCtrEditor
|
4
|
+
def initialize(plaintext, key: Random.new.bytes(16), nonce: rand(0..0x0000FF))
|
5
|
+
@plaintext = plaintext
|
6
|
+
@key = key
|
7
|
+
@nonce = nonce
|
8
|
+
@ciphertext = plaintext.encrypt_ctr(key: key, nonce: nonce)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Offset is in bytes
|
12
|
+
# Does not mutate @ciphetext or @plaintext
|
13
|
+
def edit(offset: ,with: )
|
14
|
+
previous = ciphertext[0...offset]
|
15
|
+
after = ciphertext[(offset + with.bytesize)..-1]
|
16
|
+
edited = with.encrypt_ctr(nonce: nonce,
|
17
|
+
key: key,
|
18
|
+
start_counter: offset)
|
19
|
+
previous + edited + after
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :plaintext, :key, :nonce, :ciphertext
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding; ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module BlackBoxes
|
4
|
+
class CbcBitflipTarget
|
5
|
+
def initialize(key: Random.new.bytes(16), iv: Random.new.bytes(16))
|
6
|
+
@key = key
|
7
|
+
@iv = iv
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(input)
|
11
|
+
str = prefix + input.gsub(/;|=/, "") + suffix
|
12
|
+
str.encrypt_cbc(key: key, blocksize: 16, iv: iv)
|
13
|
+
end
|
14
|
+
|
15
|
+
def is_admin?(crypted)
|
16
|
+
dec = crypted.decrypt_cbc(key: key, blocksize: 16, iv: iv)
|
17
|
+
dec.include?(";admin=true;")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :key, :iv
|
23
|
+
|
24
|
+
def prefix
|
25
|
+
"comment1=cooking%20MCs;userdata="
|
26
|
+
end
|
27
|
+
|
28
|
+
def suffix
|
29
|
+
";comment2=%20like%20a%20pound%20of%20bacon"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding; ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module BlackBoxes
|
4
|
+
class CbcIvEqualsKeyTarget
|
5
|
+
def initialize(key: Random.new.bytes(16))
|
6
|
+
@key = key
|
7
|
+
end
|
8
|
+
|
9
|
+
def encrypt(input)
|
10
|
+
str = prefix + input.gsub(/;|=/, "") + suffix
|
11
|
+
str.encrypt_cbc(key: key, blocksize: 16, iv: key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def is_admin?(crypted)
|
15
|
+
dec = crypted.decrypt_cbc(key: key, blocksize: 16, iv: key)
|
16
|
+
dec.each_byte do |byte|
|
17
|
+
raise RuntimeError.new("Invalid byte in #{dec}") if byte > '~'.ord
|
18
|
+
end
|
19
|
+
dec.include?(";admin=true;")
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :key
|
25
|
+
|
26
|
+
def prefix
|
27
|
+
"comment1=cooking%20MCs;userdata="
|
28
|
+
end
|
29
|
+
|
30
|
+
def suffix
|
31
|
+
";comment2=%20like%20a%20pound%20of%20bacon"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module BlackBoxes
|
3
|
+
class CbcPaddingOracle
|
4
|
+
|
5
|
+
attr_reader :ciphertext, :plaintext
|
6
|
+
|
7
|
+
def initialize(key: Random.new.bytes(16), iv: Random.new.bytes(16))
|
8
|
+
@key = key
|
9
|
+
@iv = iv
|
10
|
+
@ciphertext = text.encrypt_cbc(key: key, iv: iv, blocksize: 16)
|
11
|
+
@plaintext = text
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(str)
|
15
|
+
begin
|
16
|
+
!!str.
|
17
|
+
decrypt_cbc(key: key, iv: iv, blocksize: 16, strip_padding: false).
|
18
|
+
without_pkcs7_padding(16, raise_error: true)
|
19
|
+
rescue ArgumentError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :key, :iv
|
27
|
+
|
28
|
+
def text
|
29
|
+
@text ||= %w(
|
30
|
+
MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=
|
31
|
+
MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=
|
32
|
+
MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==
|
33
|
+
MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==
|
34
|
+
MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl
|
35
|
+
MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==
|
36
|
+
MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==
|
37
|
+
MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=
|
38
|
+
MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=
|
39
|
+
MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93
|
40
|
+
).map(&:from_base64).sample
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding; ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module BlackBoxes
|
4
|
+
class CtrBitflipTarget
|
5
|
+
def initialize(key: Random.new.bytes(16), nonce: rand(0..0x0000FFFF))
|
6
|
+
@key = key
|
7
|
+
@nonce = nonce
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(input)
|
11
|
+
str = prefix + input.gsub(/;|=/, "") + suffix
|
12
|
+
str.encrypt_ctr(key: key, nonce: nonce)
|
13
|
+
end
|
14
|
+
|
15
|
+
def is_admin?(crypted)
|
16
|
+
crypted.decrypt_ctr(key: key, nonce: nonce).include?(";admin=true;")
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :key, :nonce
|
22
|
+
|
23
|
+
def prefix
|
24
|
+
"comment1=cooking%20MCs;userdata="
|
25
|
+
end
|
26
|
+
|
27
|
+
def suffix
|
28
|
+
";comment2=%20like%20a%20pound%20of%20bacon"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module BlackBoxes
|
3
|
+
class DSAKeypair
|
4
|
+
def initialize(p: DSA_P, q: DSA_Q, g: DSA_G, private_key: nil, dangerous: false)
|
5
|
+
@p = p
|
6
|
+
@q = q
|
7
|
+
@g = g
|
8
|
+
@private_key = numberize(private_key) unless private_key.nil?
|
9
|
+
@safe = !dangerous
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :p, :q, :g, :safe
|
13
|
+
|
14
|
+
def sign(m, k: nil)
|
15
|
+
r = s = 0
|
16
|
+
k ||= rand(2...q)
|
17
|
+
loop do
|
18
|
+
r = g.modpow(k, p) % q
|
19
|
+
next if safe && r == 0
|
20
|
+
digest = CryptoToolchain::Utilities::SHA1.digest(m).to_number
|
21
|
+
s = k.modinv(q) * ( digest + (private_key * r)) % q
|
22
|
+
next if safe && s == 0
|
23
|
+
return [r.to_bin_string, s.to_bin_string]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def verify(m, r: , s: , public_key: self.public_key)
|
28
|
+
s = s.to_number
|
29
|
+
r = r.to_number
|
30
|
+
if safe && !(0 < r && r < q) && (0 < s && s < q)
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
w = s.invmod(q)
|
34
|
+
u_1 = (CryptoToolchain::Utilities::SHA1.digest(m).to_number * w) % q
|
35
|
+
u_2 = (r * w) % q
|
36
|
+
# a*b % n = [(a % n) * (b % n)] % m
|
37
|
+
v = ((g.modpow(u_1, p) * public_key.modpow(u_2, p)) % p) % q
|
38
|
+
v == r
|
39
|
+
end
|
40
|
+
|
41
|
+
def private_key
|
42
|
+
@private_key ||= rand(1..DSA_Q)
|
43
|
+
end
|
44
|
+
|
45
|
+
def public_key
|
46
|
+
@public_key ||= g.modpow(private_key, p)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
class Hash
|
3
|
+
def symbolize_keys
|
4
|
+
map do |k, v|
|
5
|
+
[k.to_sym, v]
|
6
|
+
end.to_h
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module CryptoToolchain
|
11
|
+
module BlackBoxes
|
12
|
+
class EcbCutAndPasteTarget
|
13
|
+
def initialize(key: String.random_bytes(16))
|
14
|
+
@key = key
|
15
|
+
end
|
16
|
+
|
17
|
+
def cookie_for(email)
|
18
|
+
{
|
19
|
+
email: email.gsub(/&|=/, ""),
|
20
|
+
uid: 10,
|
21
|
+
role: "user"
|
22
|
+
}.each_with_object([]) do |(k, v), memo|
|
23
|
+
memo << "#{k}=#{v}"
|
24
|
+
end.join("&")
|
25
|
+
end
|
26
|
+
alias_method :profile_for, :cookie_for
|
27
|
+
|
28
|
+
def encrypted_profile_for(email)
|
29
|
+
profile_for(email).encrypt_ecb(key: key, blocksize: 16)
|
30
|
+
end
|
31
|
+
alias_method :encrypt, :encrypted_profile_for
|
32
|
+
|
33
|
+
def decrypt(enc)
|
34
|
+
enc.
|
35
|
+
decrypt_ecb(key: key, blocksize: 16).
|
36
|
+
split("&").
|
37
|
+
map do |str|
|
38
|
+
k, v = str.split("=")
|
39
|
+
[k, v || ""]
|
40
|
+
end.
|
41
|
+
to_h.
|
42
|
+
symbolize_keys
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :key
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module BlackBoxes
|
4
|
+
class EcbInterpolateChosenPlaintextOracle
|
5
|
+
MYSTERY_TEXT = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"
|
6
|
+
|
7
|
+
def initialize(key: String.random_bytes(16))
|
8
|
+
@key = key
|
9
|
+
end
|
10
|
+
|
11
|
+
def encrypt(plaintext)
|
12
|
+
obfuscate(plaintext).encrypt_ecb(key: key, blocksize: 16)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :key
|
18
|
+
|
19
|
+
def obfuscate(str)
|
20
|
+
"#{prefix}#{str}#{MYSTERY_TEXT.from_base64}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def prefix
|
24
|
+
@prefix ||= String.random_bytes(rand(1..64))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module BlackBoxes
|
3
|
+
class EcbOrCbcEncryptor
|
4
|
+
ENCRYPTION_ALGORITHMS = %i(ebc cbc).freeze
|
5
|
+
attr_reader :key, :plaintext
|
6
|
+
|
7
|
+
def initialize(plaintext, algorithm: random_algorithm)
|
8
|
+
raise ArgumentError.new("Unsupported algorithm #{algorithm}") unless ENCRYPTION_ALGORITHMS.include? algorithm
|
9
|
+
@plaintext = plaintext
|
10
|
+
@key = String.random_bytes(16)
|
11
|
+
@algorithm = algorithm
|
12
|
+
end
|
13
|
+
|
14
|
+
def encrypt(_algo = algorithm)
|
15
|
+
case _algo
|
16
|
+
when :ecb
|
17
|
+
encrypt_ecb
|
18
|
+
when :cbc
|
19
|
+
encrypt_cbc
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def obfuscate(text)
|
26
|
+
append_len = (rand(5..10))
|
27
|
+
prepend_len = (rand(5..10))
|
28
|
+
"#{String.random_bytes(append_len)}#{text}#{String.random_bytes(prepend_len)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def encrypt_ecb
|
32
|
+
obfuscate(plaintext).encrypt_ecb(key: key, blocksize: 16)
|
33
|
+
end
|
34
|
+
|
35
|
+
def encrypt_cbc
|
36
|
+
obfuscate(plaintext).encrypt_cbc(key: key,
|
37
|
+
iv: String.random_bytes(16),
|
38
|
+
blocksize: 16)
|
39
|
+
end
|
40
|
+
|
41
|
+
def random_algorithm
|
42
|
+
ENCRYPTION_ALGORITHMS[rand(2)]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
module CryptoToolchain
|
3
|
+
module BlackBoxes
|
4
|
+
class EcbPrependChosenPlaintextOracle
|
5
|
+
MYSTERY_TEXT = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"
|
6
|
+
def initialize(key: String.random_bytes(16))
|
7
|
+
@key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(plaintext)
|
11
|
+
obfuscate(plaintext).encrypt_ecb(key: key, blocksize: 16)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :key
|
17
|
+
|
18
|
+
def obfuscate(str)
|
19
|
+
"#{str}#{MYSTERY_TEXT.from_base64}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CryptoToolchain
|
2
|
+
module BlackBoxes
|
3
|
+
class MD4Mac
|
4
|
+
attr_reader :key
|
5
|
+
|
6
|
+
def initialize(key: Random.new.bytes(16))
|
7
|
+
@key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def mac(str)
|
11
|
+
concat = key + str
|
12
|
+
CryptoToolchain::Utilities::MD4.hexdigest(concat)
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?(message: , mac: )
|
16
|
+
self.mac(message) == mac
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|