crypto-toolbox 0.1.6 → 0.1.7
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 +4 -4
- data/lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb +102 -0
- data/lib/crypto-toolbox/analyzers/padding_oracle/oracles/http_oracle.rb +37 -0
- data/lib/crypto-toolbox/analyzers/padding_oracle/oracles/tcp_oracle.rb +51 -0
- data/lib/crypto-toolbox/analyzers/padding_oracle.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb26fa406648e8e856c7aaf45c86b9c78b6cff6d
|
4
|
+
data.tar.gz: c9dcc5cd246e4547fd3e22c8be90725dd496aa08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45e036a7da35bcead7b46b3036de35d73f0cb7642f4f6cc9a8edb316372b6304134b2a18babbad1bd044fc0d75d1572c64ccb18d52c2667bd10bb9a02056b493
|
7
|
+
data.tar.gz: 129d788d0a7139a2e2399c496cb83522ead7ff6c6f6c61530bb1c1576f7ec8f41277b7378e9ea5ae289c59db4563e35978cd47d372fb818ebf0227cae7efa597
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'crypto-toolbox/analyzers/padding_oracle/oracles/http_oracle.rb'
|
2
|
+
require 'crypto-toolbox/analyzers/padding_oracle/oracles/tcp_oracle.rb'
|
3
|
+
|
4
|
+
|
5
|
+
module Analyzers
|
6
|
+
module PaddingOracle
|
7
|
+
|
8
|
+
class Analyzer
|
9
|
+
class FailedAnalysis < RuntimeError; end
|
10
|
+
attr_reader :result
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(oracle_class = ::Analyzers::PaddingOracle::Oracles::TcpOracle)
|
14
|
+
@result = [ ]
|
15
|
+
@oracle = oracle_class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def analyze(cipher)
|
20
|
+
blocks = CryptBuffer.from_hex(cipher).chunks_of(16)
|
21
|
+
|
22
|
+
# start with the second to last block to manipulate the final block ( cbc xor behaviour )
|
23
|
+
(blocks.length - 1).downto(1) do |block_index|
|
24
|
+
result_part = []
|
25
|
+
# manipulate each byte of the 16 byte block
|
26
|
+
1.upto(blocks[block_index -1 ].length) do |pad_index|
|
27
|
+
@oracle.connect
|
28
|
+
|
29
|
+
jot("processing byte #{pad_index} in block: #{block_index - 1} => #{block_index}",debug: true)
|
30
|
+
byte = read_byte(pad_index,result_part,blocks,block_index)
|
31
|
+
result_part.unshift byte
|
32
|
+
|
33
|
+
@oracle.disconnect
|
34
|
+
end
|
35
|
+
result.unshift result_part
|
36
|
+
end
|
37
|
+
jot(CryptBuffer(result.flatten).chars.inspect,debug: false)
|
38
|
+
jot("stripping padding!",debug: true)
|
39
|
+
jot(CryptBuffer(result.flatten).strip_padding.str,debug: false)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
private
|
44
|
+
def jot(message, debug: false)
|
45
|
+
if debug == false || ENV["DEBUG_ANALYSIS"]
|
46
|
+
puts message
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def apply_found_bytes(buf,cur_result,pad_index)
|
51
|
+
# first we have to apply all the already found bytes
|
52
|
+
|
53
|
+
|
54
|
+
# NOTE: to easily xor all already found byte and the current padding value
|
55
|
+
# We build up a byte-array with all the known values and "left-pad" them with zeros
|
56
|
+
|
57
|
+
other = ([0] * ( buf.length - cur_result.length)) + cur_result.map{|x| x ^ pad_index }
|
58
|
+
# => [0,0,0,...,cur[n] ^ pad_index,... ]
|
59
|
+
buf.xor(other)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def read_byte(pad_index,cur_result,blocks,block_index)
|
64
|
+
#iv, first, second, last
|
65
|
+
jot(cur_result.inspect,debug: true)
|
66
|
+
|
67
|
+
# create a copy to mess with without changing to current block
|
68
|
+
forge_buf = blocks[block_index - 1].dup
|
69
|
+
|
70
|
+
forge_buf = apply_found_bytes(forge_buf,cur_result,pad_index)
|
71
|
+
|
72
|
+
1.upto 256 do |guess|
|
73
|
+
bytes = forge_buf.bytes.dup
|
74
|
+
new_byte = forge_buf[-1 * pad_index] ^ guess ^ pad_index
|
75
|
+
|
76
|
+
bytes[-1 * pad_index] = new_byte
|
77
|
+
|
78
|
+
oracle_blocks = blocks[0,block_index+1].map(&:bytes)
|
79
|
+
oracle_blocks[block_index -1 ] = bytes
|
80
|
+
|
81
|
+
input = oracle_blocks.flatten
|
82
|
+
|
83
|
+
# skip the first correct guess on the first iteration of the first block
|
84
|
+
# otherwise the resulting ciphertext would eq the original input
|
85
|
+
#next if input == blocks.map(&:bytes).flatten
|
86
|
+
next if guess == pad_index && guess == 1 && block_index == 2
|
87
|
+
|
88
|
+
block_amount = block_index + 1
|
89
|
+
if @oracle.valid_padding?(input,block_amount)
|
90
|
+
return guess
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
raise FailedAnalysis, "No padding found... this should neve happen..."
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module Analyzers
|
3
|
+
module PaddingOracle
|
4
|
+
module Oracles
|
5
|
+
class HttpOracle
|
6
|
+
def initialize
|
7
|
+
require 'net/http'
|
8
|
+
@domain = "crypto-class.appspot.com"
|
9
|
+
@uri_base = "/po?er="
|
10
|
+
@port = 80
|
11
|
+
end
|
12
|
+
def connect
|
13
|
+
true
|
14
|
+
end
|
15
|
+
def disconnect
|
16
|
+
true
|
17
|
+
end
|
18
|
+
def valid_padding?(input,block_amount)
|
19
|
+
|
20
|
+
uri = @uri_base + input.hex
|
21
|
+
|
22
|
+
Net::HTTP.start(@domain,@port) do |http|
|
23
|
+
res = http.request(Net::HTTP::Get.new(uri))
|
24
|
+
code = res.code.to_i
|
25
|
+
sleep 0.001
|
26
|
+
|
27
|
+
# -> howto check this ? (block_index == 3 && pad_index == 9 && code == 200 )
|
28
|
+
(code == 404 || code == 200)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'crypto-toolbox'
|
4
|
+
|
5
|
+
module Analyzers
|
6
|
+
module PaddingOracle
|
7
|
+
module Oracles
|
8
|
+
|
9
|
+
class TcpOracle
|
10
|
+
def initialize
|
11
|
+
require "socket"
|
12
|
+
require_relative "./tcp_oracle.rb"
|
13
|
+
|
14
|
+
@hostname = '54.165.60.84'
|
15
|
+
@port = 80
|
16
|
+
@socket = nil
|
17
|
+
end
|
18
|
+
def connect
|
19
|
+
@socket = TCPSocket.open(@hostname,@port)
|
20
|
+
end
|
21
|
+
|
22
|
+
def disconnect
|
23
|
+
if @socket
|
24
|
+
@socket.close
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid_padding?(input,block_amount)
|
29
|
+
ret = send_msg(input, block_amount)
|
30
|
+
!ret.zero?
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def send_msg(input,block_amount)
|
35
|
+
connect unless connected?
|
36
|
+
|
37
|
+
msg = ([block_amount] + input + [0]).map(&:chr)
|
38
|
+
@socket.write(msg.join(""))
|
39
|
+
@socket.read(2).to_i
|
40
|
+
end
|
41
|
+
def connected?
|
42
|
+
!!@socket
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'crypto-toolbox/analyzers/padding_oracle/analyzer.rb'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crypto-toolbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dennis Sivia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aes
|
@@ -48,6 +48,10 @@ extra_rdoc_files: []
|
|
48
48
|
files:
|
49
49
|
- bin/break-vigenere-xor
|
50
50
|
- lib/crypto-toolbox.rb
|
51
|
+
- lib/crypto-toolbox/analyzers/padding_oracle.rb
|
52
|
+
- lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb
|
53
|
+
- lib/crypto-toolbox/analyzers/padding_oracle/oracles/http_oracle.rb
|
54
|
+
- lib/crypto-toolbox/analyzers/padding_oracle/oracles/tcp_oracle.rb
|
51
55
|
- lib/crypto-toolbox/analyzers/vigenere_xor.rb
|
52
56
|
- lib/crypto-toolbox/ciphers/caesar.rb
|
53
57
|
- lib/crypto-toolbox/ciphers/rot13.rb
|