Class: CryptoToolchain::Tools::EcbPrependChosenPlaintextAttack

Inherits:
Object
  • Object
show all
Includes:
DetermineBlocksize
Defined in:
lib/crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack.rb

Constant Summary collapse

PAD =
"A".freeze

Instance Method Summary collapse

Methods included from DetermineBlocksize

#blocksize

Constructor Details

#initialize(oracle: CryptoToolchain::BlackBoxes::EcbPrependChosenPlaintextOracle.new) ⇒ EcbPrependChosenPlaintextAttack

oracle must return an encrypted string via #encrypt



9
10
11
12
13
14
# File 'lib/crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack.rb', line 9

def initialize(oracle: CryptoToolchain::BlackBoxes::EcbPrependChosenPlaintextOracle.new)
  @oracle = oracle
  unless oracle.encrypt(PAD * blocksize * 10).is_ecb_encrypted?(@blocksize)
    raise ArgumentError.new("Oracle does not appear to encrypt with ECB")
  end
end

Instance Method Details

#executeObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/crypto_toolchain/tools/ecb_prepend_chosen_plaintext_attack.rb', line 16

def execute
  (0..Float::INFINITY).each_with_object("") do |block_index, solved|
    from_block = (0...blocksize).each_with_object("") do |i, solved_in_block|
      padding_length = blocksize - (solved_in_block.bytes.length) - 1
      padding = PAD * padding_length
      target = oracle.encrypt(padding).in_blocks(blocksize)[block_index]
      dict = (0..255).map(&:chr).each_with_object({}) do |chr, memo|
        guess = padding + solved + solved_in_block + chr
        output = oracle.encrypt(guess).in_blocks(blocksize)[block_index]
        memo[output] = chr
        break(memo) if output == target
      end
      if !dict.has_key?(target)
        return "#{solved}#{solved_in_block}"
      end
      solved_in_block << dict.fetch(target)
    end
    solved << from_block
  end
end