crypto_toolchain 0.1.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 +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
|