Last active
August 29, 2015 14:05
-
-
Save drewblas/00984c76d39fad59871f to your computer and use it in GitHub Desktop.
Encryption Mistake Example
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
require 'openssl' | |
=begin | |
Most plaintext must be fed as a string or a binary object to be encrypted. | |
However, it's often possible to mis-decode the plaintext before encrypting it. | |
i.e. If it's received as a string in JSON, you often don't know if the string | |
is an encoded representation (e.g. plain, hex encoded, base64 encoded, etc) | |
Example: | |
If the message to encrypt is received as "48656c6c6f" (which is "Hello" in hex), | |
it's possible to accidentally encrypt "48656c6c6f" instead of "Hello". | |
When you decrypt, you'll get back whatever you started with, so it's easy to | |
never know you are encrypting incorrectly. | |
This results in a plaintext input where the variation per-byte is very small. | |
If you accidentally encrypt "01001000" as an 8-byte string instead of a single | |
byte (0x48, 'H'), then each resulting ciphertext byte is the result of only | |
one of two inputs: '0' or '1'. | |
Question: | |
* Is it INSECURE to make this mistake? | |
* Is the ciphertext somehow easier to break because you used the wrong plaintext? | |
* What if you make this same mistake with the KEY instead of the plaintext? | |
=end | |
real_plaintext = "Hello" # 5 bytes | |
plaintext_1 = real_plaintext.unpack('H*').first | |
puts plaintext_1 # 48 65 6c 6c 6f | |
plaintext_2 = real_plaintext.unpack('B*').first | |
puts plaintext_2 # 01001000 01100101 01101100 01101100 01101111 | |
plaintext_3 = [real_plaintext].pack('m') | |
puts plaintext_3 # SGVsbG8= | |
# Stream cipher used here to make it more obvious about | |
# the different resulting lengths | |
def encrypt(str, method='aes-256-ctr') | |
cipher = OpenSSL::Cipher::Cipher.new(method) | |
cipher.encrypt | |
key = cipher.key = cipher.random_key | |
iv = cipher.iv = cipher.random_iv | |
cipher.update(str) + cipher.final | |
end | |
puts "Result of real_plaintext:" | |
result = encrypt(real_plaintext) | |
puts "Len: #{result.length} - #{result.unpack('H*').first}" | |
puts "Result of plaintext_1:" | |
result = encrypt(plaintext_1) | |
puts "Len: #{result.length} - #{result.unpack('H*').first}" | |
puts "Result of plaintext_2:" | |
result = encrypt(plaintext_2) | |
puts "Len: #{result.length} - #{result.unpack('H*').first}" | |
puts "Result of plaintext_3:" | |
result = encrypt(plaintext_3) | |
puts "Len: #{result.length} - #{result.unpack('H*').first}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment