Skip to content

Instantly share code, notes, and snippets.

@le4ker
Last active September 17, 2023 09:56
Show Gist options
  • Save le4ker/02c225e4ebe6c596a7519ebead84091c to your computer and use it in GitHub Desktop.
Save le4ker/02c225e4ebe6c596a7519ebead84091c to your computer and use it in GitHub Desktop.
A demonstration of Padding Oracle Attack
# # # # # # # # # # # # # # # # # # # # # # # # #
# Demonstration of Padding Oracle Attack #
# Author: Panos Sakkos <panos.sakkos@gmail.com> #
# Date: May 2017 #
# License: MIT #
# # # # # # # # # # # # # # # # # # # # # # # # #
require 'openssl'
class PaddingOracle
def encrypt(plaintext)
cipher = OpenSSL::Cipher::AES.new(256, :CBC)
cipher.encrypt
@key = cipher.random_key
iv = cipher.random_iv
ciphertext = cipher.update(plaintext) + cipher.final
return iv + ciphertext
end
def decrypt(ciphertext)
decipher = OpenSSL::Cipher::AES.new(256, :CBC)
decipher.decrypt
decipher.key = @key
decipher.iv = ciphertext[0..15]
# The Oracle will leak if whether the padding is correct or not in the .final method
plaintext = decipher.update(ciphertext[16..(ciphertext.length - 1)]) + decipher.final
# No plaintext returned
end
end
plaintext = 'This is a top secret message!!!'
oracle = PaddingOracle.new()
intercepted_ciphertext = oracle.encrypt(plaintext)
recovered_plaintext = ''
to = intercepted_ciphertext.length - 1
from = to - 31
while from >= 0
target_blocks = intercepted_ciphertext[from..to]
i = 15
padding = 0x01
recovered_block = ''
while i >= 0
# For each byte of the block
for c in 0x00..0xff
# For each possible byte value
chosen_ciphertext = target_blocks.dup
# Set the bytes that we have already recovered in the block
j = recovered_block.length - 1
ii = 15
while j >= 0
chosen_ciphertext[ii] = (chosen_ciphertext.bytes[ii] ^ recovered_block.bytes[j] ^ padding).chr
j -= 1
ii -= 1
end
# Guess the i-th byte of the block
chosen_ciphertext[i] = (chosen_ciphertext.bytes[i] ^ c ^ padding).chr
begin
# Ask the Oracle
oracle.decrypt(chosen_ciphertext)
# The Oracle said Yes, move to the next byte
recovered_block = c.chr + recovered_block
next
rescue OpenSSL::Cipher::CipherError
# The Oracle said No, try the next possible value of the byte
end
end
i -= 1
padding += 0x01
end
recovered_plaintext = recovered_block + recovered_plaintext
# Move to the next block
from -= 16
to -= 16
end
puts recovered_plaintext
# This is a top secret message!!!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment