class Analyzers::PaddingOracle::Analyzer
Attributes
Public Class Methods
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 10 def initialize(oracle = CryptoToolbox::Oracles::PaddingOracle::TcpOracle.new) @result = [ ] @oracle = oracle end
Public Instance Methods
start with the second to last block to manipulate the final block ( cbc xor behaviour ) from there on we move to the left until we have used the first block (iv) to decrypt the second blick ( first plain text block )
we have to manipulate the block before the one we want to change xxxxxxxxx xxxxxxxxx xxxxxxxxxx changing this byte ^- will change ^- this byte at decryption
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 22 def analyze(cipher) blocks = CryptBuffer.from_hex(cipher).chunks_of(16) # ranges cant be from high to low (1..(blocks.length() -1)).reverse_each do |block_index| result.unshift analyse_block(blocks,block_index) end plaintext = CryptBuffer(result.flatten) report_result(plaintext) plaintext.strip_padding end
Private Instance Methods
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 37 def analyse_block(blocks,block_index) block_result = [] # manipulate each byte of the 16 byte block 1.upto(blocks[block_index -1].length) do |pad_index| with_oracle_connection do jot("processing byte #{pad_index} in block: #{block_index -1} => #{block_index}",debug: true) byte = read_byte(pad_index,block_result,blocks,block_index) block_result.unshift byte end end block_result end
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 63 def apply_found_bytes(buf,cur_result,pad_index) # first we have to apply all the already found bytes # NOTE: to easily xor all already found byte and the current padding value # We build up a byte-array with all the known values and "left-pad" them with zeros other = ([0] * ( buf.length - cur_result.length)) + cur_result.map{|x| x ^ pad_index } # => [0,0,0,...,cur[n] ^ pad_index,... ] buf.xor(other) end
Create a subset to only send the blocks we still need to decrypt. manipulate the byte with a padding-index and a guess map the crypt buffer array to a flat array of integers ( representing bytes )
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 103 def assemble_oracle_input(buffer,blocks,block_index,pad_index,guess) # the bytes from the subset we will send to the padding oracle subset = blocks[0,block_index+1] subset[block_index -1 ] = buffer.xor_at([guess,pad_index], -1 * pad_index) subset.map(&:bytes).flatten end
include the block after the index, since this is the one effected by our manipulation. ( due to cbc mode )
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 96 def block_amount(index) index +1 end
the blocks are: xxxxxxxx xxxxxxxx xxxxxxxx [..] ^- IV ^- first ^- second …
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 76 def read_byte(pad_index,cur_result,blocks,block_index) jot(cur_result.inspect,debug: true) # apply all the current-result bytes to the block corresponding to <block_index> # and store the result in a buffer we will mess with forge_buf = apply_found_bytes(blocks[block_index - 1],cur_result,pad_index) 1.upto 255 do |guess| input = assemble_oracle_input(forge_buf,blocks,block_index,pad_index,guess) next if skip?(pad_index,block_index,guess,cur_result) return guess if @oracle.valid_padding?(input,block_amount(block_index)) end raise FailedAnalysis, "No padding found... this should never happen..." end
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 51 def report_result(result) jot(result.chars.inspect,debug: true) jot("stripping padding!",debug: true) jot(result.strip_padding.str,debug: true) end
In case of the first iteration there is a special case to skip: 1) No other blocks have been decrypted yet ( result.empty? ) 2) No bytes of the current block have been processed yet ( block_result_empty? ) 3) guess xor pad-index does not modify anything ( eq zero )
> This would leed to the original ciphertext without any modification beeing sent¶ ↑
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 115 def skip?(pad_index,block_index,guess,block_result) result.empty? && block_result.empty? && (guess ^ pad_index).zero? end
# File lib/crypto-toolbox/analyzers/padding_oracle/analyzer.rb, line 57 def with_oracle_connection @oracle.connect yield @oracle.disconnect end