Class: PDF::Reader::StandardSecurityHandler

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

Overview

class creates interface to encrypt dictionary for use in Decrypt

Constant Summary collapse

PassPadBytes =

7.6.3.3 Encryption Key Algorithm (pp61)

needs a document’s user password to build a key for decrypting an encrypted PDF document

[ 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a ]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ StandardSecurityHandler

Returns a new instance of StandardSecurityHandler.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/pdf/reader/standard_security_handler.rb', line 48

def initialize(opts = {})
  @key_length    = opts[:key_length].to_i/8
  @revision      = opts[:revision].to_i
  @owner_key     = opts[:owner_key]
  @user_key      = opts[:user_key]
  @permissions   = opts[:permissions].to_i
  @encryptMeta   = opts.fetch(:encrypted_metadata, true)
  @file_id       = opts[:file_id] || ""
  @encrypt_key   = build_standard_key(opts[:password] || "")

  if @key_length != 5 && @key_length != 16
    msg = "StandardSecurityHandler only supports 40 and 128 bit\
           encryption (#{@key_length * 8}bit)"
    raise ArgumentError, msg
  end
end

Instance Attribute Details

#encrypt_keyObject (readonly)

Returns the value of attribute encrypt_key.



45
46
47
# File 'lib/pdf/reader/standard_security_handler.rb', line 45

def encrypt_key
  @encrypt_key
end

#file_idObject (readonly)

Returns the value of attribute file_id.



46
47
48
# File 'lib/pdf/reader/standard_security_handler.rb', line 46

def file_id
  @file_id
end

#key_lengthObject (readonly)

Returns the value of attribute key_length.



45
46
47
# File 'lib/pdf/reader/standard_security_handler.rb', line 45

def key_length
  @key_length
end

#owner_keyObject (readonly)

Returns the value of attribute owner_key.



46
47
48
# File 'lib/pdf/reader/standard_security_handler.rb', line 46

def owner_key
  @owner_key
end

#passwordObject (readonly)

Returns the value of attribute password.



46
47
48
# File 'lib/pdf/reader/standard_security_handler.rb', line 46

def password
  @password
end

#permissionsObject (readonly)

Returns the value of attribute permissions.



46
47
48
# File 'lib/pdf/reader/standard_security_handler.rb', line 46

def permissions
  @permissions
end

#revisionObject (readonly)

Returns the value of attribute revision.



45
46
47
# File 'lib/pdf/reader/standard_security_handler.rb', line 45

def revision
  @revision
end

#user_keyObject (readonly)

Returns the value of attribute user_key.



46
47
48
# File 'lib/pdf/reader/standard_security_handler.rb', line 46

def user_key
  @user_key
end

Class Method Details

.supports?(encrypt) ⇒ Boolean

This handler supports all RC4 encryption that follows the PDF spec. It does not support AES encryption that was added in later versions of the spec.

Returns:

  • (Boolean)


67
68
69
70
71
72
73
74
75
# File 'lib/pdf/reader/standard_security_handler.rb', line 67

def self.supports?(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 &&
    (version <= 3 || (version == 4 && algorithm != :AESV2))
end

Instance Method Details

#decrypt(buf, ref) ⇒ Object

7.6.2 General Encryption Algorithm

Algorithm 1: Encryption of data using the RC4 or AES algorithms

used to decrypt RC4 encrypted PDF streams (buf)

buf - a string to decrypt ref - a PDF::Reader::Reference for the object to decrypt



86
87
88
89
90
91
92
93
# File 'lib/pdf/reader/standard_security_handler.rb', line 86

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 ) }
  length = objKey.length < 16 ? objKey.length : 16
  rc4 = RC4.new( Digest::MD5.digest(objKey)[0,length] )
  rc4.decrypt(buf)
end