diff --git a/lib/pdf/reader/aes_v2_security_handler.rb b/lib/pdf/reader/aes_v2_security_handler.rb index a76b12c5..566f7de6 100644 --- a/lib/pdf/reader/aes_v2_security_handler.rb +++ b/lib/pdf/reader/aes_v2_security_handler.rb @@ -21,20 +21,30 @@ def initialize(key) # # version == 4 and CFM == AESV2 # + # used to decrypt PDF streams (buf). Input data should be in bytesizes of + # a multiple of 16, anything else is an error. The first 16 bytes are the initialization + # vector, so any input of exactly 16 bytes decrypts to an empty string + # # buf - a string to decrypt # ref - a PDF::Reader::Reference for the object to decrypt # def decrypt( buf, ref ) - objKey = @encrypt_key.dup - (0..2).each { |e| objKey << (ref.id >> e*8 & 0xFF ) } - (0..1).each { |e| objKey << (ref.gen >> e*8 & 0xFF ) } - objKey << 'sAlT' # Algorithm 1, b) - length = objKey.length < 16 ? objKey.length : 16 - cipher = OpenSSL::Cipher.new("AES-#{length << 3}-CBC") - cipher.decrypt - cipher.key = Digest::MD5.digest(objKey)[0,length] - cipher.iv = buf[0..15] - cipher.update(buf[16..-1]) + cipher.final + if buf.bytesize % 16 > 0 + raise PDF::Reader::MalformedPDFError.new("Ciphertext not a multiple of 16") + elsif buf.bytesize == 16 + return "" + else + objKey = @encrypt_key.dup + (0..2).each { |e| objKey << (ref.id >> e*8 & 0xFF ) } + (0..1).each { |e| objKey << (ref.gen >> e*8 & 0xFF ) } + objKey << 'sAlT' # Algorithm 1, b) + length = objKey.length < 16 ? objKey.length : 16 + cipher = OpenSSL::Cipher.new("AES-#{length << 3}-CBC") + cipher.decrypt + cipher.key = Digest::MD5.digest(objKey)[0,length] + cipher.iv = buf[0..15] + cipher.update(buf[16..-1]) + cipher.final + end end end diff --git a/lib/pdf/reader/aes_v3_security_handler.rb b/lib/pdf/reader/aes_v3_security_handler.rb index 3794731b..fdfe1030 100644 --- a/lib/pdf/reader/aes_v3_security_handler.rb +++ b/lib/pdf/reader/aes_v3_security_handler.rb @@ -21,17 +21,25 @@ def initialize(key) # # Algorithm 1: Encryption of data using the RC4 or AES algorithms # - # used to decrypt RC4/AES encrypted PDF streams (buf) + # used to decrypt RC4/AES encrypted PDF streams (buf). Input data should be in bytesizes of + # a multiple of 16, anything else is an error. The first 16 bytes are the initialization + # vector, so any input of exactly 16 bytes decrypts to an empty string # # buf - a string to decrypt # ref - a PDF::Reader::Reference for the object to decrypt # def decrypt( buf, ref ) - cipher = OpenSSL::Cipher.new(@cipher) - cipher.decrypt - cipher.key = @encrypt_key.dup - cipher.iv = buf[0..15] - cipher.update(buf[16..-1]) + cipher.final + if buf.bytesize % 16 > 0 + raise PDF::Reader::MalformedPDFError.new("Ciphertext not a multiple of 16") + elsif buf.bytesize == 16 + return "" + else + cipher = OpenSSL::Cipher.new(@cipher) + cipher.decrypt + cipher.key = @encrypt_key.dup + cipher.iv = buf[0..15] + cipher.update(buf[16..-1]) + cipher.final + end end end