Skip to content

Commit

Permalink
Ensure that a security handler is always initialised
Browse files Browse the repository at this point in the history
For now, we have three handlers:

* NullSecurityHandler for unencrypted files
* StandardSecurityHandler for files encrypted with pdf-spec compatible RC4 encryption
* UnimplementedSecurityHandler for files encrypted with unsupported
  algorithms, including PDF-spec compatible AES, and any proprietary
  algorithm (adobe ebooks, etc).
  • Loading branch information
yob committed Feb 25, 2017
1 parent 95a0e56 commit 81e3039
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/pdf/reader.rb
Expand Up @@ -277,6 +277,7 @@ def root
require 'pdf/reader/register_receiver'
require 'pdf/reader/null_security_handler'
require 'pdf/reader/standard_security_handler'
require 'pdf/reader/unimplemented_security_handler'
require 'pdf/reader/stream'
require 'pdf/reader/text_run'
require 'pdf/reader/page_state'
Expand Down
6 changes: 3 additions & 3 deletions lib/pdf/reader/null_security_handler.rb
Expand Up @@ -2,10 +2,10 @@

class PDF::Reader

# A null object security handler. Used when we don't support the encryption type in a file.
# A null object security handler. Used when a PDF is unencrypted.
class NullSecurityHandler
def decrypt(buf, ref)
raise PDF::Reader::EncryptedPDFError, "Unsupported encryption style"
def decrypt(buf, _ref)
buf
end
end
end
11 changes: 5 additions & 6 deletions lib/pdf/reader/object_hash.rb
Expand Up @@ -45,6 +45,7 @@ def initialize(input, opts = {})
@pdf_version = read_version
@trailer = @xref.trailer
@cache = opts[:cache] || PDF::Reader::ObjectCache.new
@sec_handler = NullSecurityHandler.new
@sec_handler = build_security_handler(opts)
end

Expand Down Expand Up @@ -286,15 +287,15 @@ def deref_internal!(key, seen)
end

def build_security_handler(opts = {})
return nil if trailer[:Encrypt].nil?
return NullSecurityHandler.new if trailer[:Encrypt].nil?

enc = deref(trailer[:Encrypt])
filter = enc.fetch(:Filter, :Standard)
version = enc.fetch(:V, 0)
if filter == :Standard && version >= 5
NullSecurityHandler.new
UnimplementedSecurityHandler.new
elsif filter == :Standard && version >= 4 && enc.fetch(:CF, {}).fetch(enc[:StmF], {}).fetch(:CFM, nil) == :AESV2
NullSecurityHandler.new
UnimplementedSecurityHandler.new
elsif filter == :Standard
encmeta = enc.has_key?(:EncryptMetadata)? enc[:EncryptMetadata].to_s == "true" : true

Expand All @@ -309,13 +310,11 @@ def build_security_handler(opts = {})
password: opts[:password]
)
else
raise PDF::Reader::EncryptedPDFError, "Unsupported encryption method (#{enc[:Filter]})"
UnimplementedSecurityHandler.new
end
end

def decrypt(ref, obj)
return obj unless sec_handler?

case obj
when PDF::Reader::Stream then
obj.data = sec_handler.decrypt(obj.data, ref)
Expand Down
12 changes: 12 additions & 0 deletions lib/pdf/reader/unimplemented_security_handler.rb
@@ -0,0 +1,12 @@
# coding: utf-8

class PDF::Reader

# Security handler for when we don't support the flavour of encryption
# used in a PDF.
class UnimplementedSecurityHandler
def decrypt(buf, ref)
raise PDF::Reader::EncryptedPDFError, "Unsupported encryption style"
end
end
end

0 comments on commit 81e3039

Please sign in to comment.