Class: PDF::Reader::SecurityHandlerFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/pdf/reader/security_handler_factory.rb

Overview

Examines the Encrypt entry of a PDF trailer (if any) and returns an object that’s able to decrypt the file.

Class Method Summary collapse

Class Method Details

.build(encrypt, doc_id, password) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/pdf/reader/security_handler_factory.rb', line 10

def self.build(encrypt, doc_id, password)
  doc_id   ||= []
  password ||= ""

  if encrypt.nil?
    NullSecurityHandler.new
  elsif standard?(encrypt)
    build_standard_handler(encrypt, doc_id, password)
  elsif standard_v5?(encrypt)
    build_v5_handler(encrypt, doc_id, password)
  else
    UnimplementedSecurityHandler.new
  end
end

.build_standard_handler(encrypt, doc_id, password) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/pdf/reader/security_handler_factory.rb', line 25

def self.build_standard_handler(encrypt, doc_id, password)
  encmeta = !encrypt.has_key?(:EncryptMetadata) || encrypt[:EncryptMetadata].to_s == "true"
  key_builder = StandardKeyBuilder.new(
    key_length: (encrypt[:Length] || 40).to_i,
    revision: encrypt[:R],
    owner_key: encrypt[:O],
    user_key: encrypt[:U],
    permissions: encrypt[:P].to_i,
    encrypted_metadata: encmeta,
    file_id: doc_id.first,
  )
  cfm = encrypt.fetch(:CF, {}).fetch(encrypt[:StmF], {}).fetch(:CFM, nil)
  if cfm == :AESV2
    AesV2SecurityHandler.new(key_builder.key(password))
  else
    Rc4SecurityHandler.new(key_builder.key(password))
  end
end

.build_v5_handler(encrypt, doc_id, password) ⇒ Object



44
45
46
47
48
49
50
51
52
# File 'lib/pdf/reader/security_handler_factory.rb', line 44

def self.build_v5_handler(encrypt, doc_id, password)
  key_builder = KeyBuilderV5.new(
    owner_key: encrypt[:O],
    user_key: encrypt[:U],
    owner_encryption_key: encrypt[:OE],
    user_encryption_key: encrypt[:UE],
  )
  AesV3SecurityHandler.new(key_builder.key(password))
end

.standard?(encrypt) ⇒ Boolean

This handler supports all encryption that follows upto PDF 1.5 spec (revision 4)

Returns:

  • (Boolean)


55
56
57
58
59
60
61
62
63
# File 'lib/pdf/reader/security_handler_factory.rb', line 55

def self.standard?(encrypt)
  return false if encrypt.nil?

  filter = encrypt.fetch(:Filter, :Standard)
  version = encrypt.fetch(:V, 0)
  algorithm = encrypt.fetch(:CF, {}).fetch(encrypt[:StmF], {}).fetch(:CFM, nil)
  (filter == :Standard) && (encrypt[:StmF] == encrypt[:StrF]) &&
    (version <= 3 || (version == 4 && ((algorithm == :V2) || (algorithm == :AESV2))))
end

.standard_v5?(encrypt) ⇒ Boolean

This handler supports both

  • AES-256 encryption defined in PDF 1.7 Extension Level 3 (‘revision 5’)

  • AES-256 encryption defined in PDF 2.0 (‘revision 6’)

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
77
# File 'lib/pdf/reader/security_handler_factory.rb', line 68

def self.standard_v5?(encrypt)
  return false if encrypt.nil?

  filter = encrypt.fetch(:Filter, :Standard)
  version = encrypt.fetch(:V, 0)
  revision = encrypt.fetch(:R, 0)
  algorithm = encrypt.fetch(:CF, {}).fetch(encrypt[:StmF], {}).fetch(:CFM, nil)
  (filter == :Standard) && (encrypt[:StmF] == encrypt[:StrF]) &&
      ((version == 5) && (revision == 5 || revision == 6) && (algorithm == :AESV3))
end