Last active
September 17, 2023 09:56
-
-
Save le4ker/02c225e4ebe6c596a7519ebead84091c to your computer and use it in GitHub Desktop.
A demonstration of Padding Oracle Attack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# # # # # # # # # # # # # # # # # # # # # # # # # | |
# 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