Class: Pdfrb::Document::Encryption

Inherits:
Object
  • Object
show all
Defined in:
lib/pdfrb/document/encryption.rb

Overview

Encryption facade. Exposes a clean API for encrypting a document (builds the /Encrypt dict, wires the security handler into the writer config) and for checking encryption status.

Usage:

doc.encryption.encrypt!(
user_password: "reader",
owner_password: "owner",
bits: 128,
permissions: %i[print copy]
)
doc.write("encrypted.pdf")

Constant Summary collapse

PERMISSION_FLAGS =
{
  print: 1 << 2,
  modify: 1 << 3,
  copy: 1 << 4,
  annotate: 1 << 5,
  fill: 1 << 8,
  extract: 1 << 9,
  assemble: 1 << 10,
  print_hq: 1 << 11,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ Encryption

Returns a new instance of Encryption.



34
35
36
# File 'lib/pdfrb/document/encryption.rb', line 34

def initialize(document)
  @document = document
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



32
33
34
# File 'lib/pdfrb/document/encryption.rb', line 32

def document
  @document
end

Class Method Details

.permission_bits(granted) ⇒ Object

Compute the /P integer: all bits set minus the denied ones.



85
86
87
88
89
90
91
# File 'lib/pdfrb/document/encryption.rb', line 85

def self.permission_bits(granted)
  base = -1
  PERMISSION_FLAGS.each do |name, bit|
    base &= ~bit unless granted.include?(name)
  end
  base
end

Instance Method Details

#decrypt!Object

Remove /Encrypt from the trailer (decrypt use case). Returns self for chaining; use encrypted? to check the result.



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/pdfrb/document/encryption.rb', line 70

def decrypt!
  trailer = document.trailer
  if trailer && trailer[:Encrypt]
    if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
      trailer.value.delete(:Encrypt)
    else
      trailer.delete(:Encrypt)
    end
    document.config["encryption.handler"] = nil
    document.config["encryption.password"] = nil
  end
  self
end

#encrypt!(user_password:, owner_password: nil, bits: 128, permissions: PERMISSION_FLAGS.keys) ⇒ Pdfrb::Model::Cos::Dictionary

Encrypt this document with a user + owner password.

Parameters:

  • user_password (String)

    the password readers need to open.

  • owner_password (String) (defaults to: nil)

    the password that grants full permissions (defaults to user_password).

  • bits (Integer) (defaults to: 128)

    key length: 40, 128 (AES-128), or 256 (AES-256 R6).

  • permissions (Array<Symbol>) (defaults to: PERMISSION_FLAGS.keys)

    granted permissions from PERMISSION_FLAGS keys; any not listed are denied.

Returns:



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/pdfrb/document/encryption.rb', line 48

def encrypt!(user_password:, owner_password: nil, bits: 128,
             permissions: PERMISSION_FLAGS.keys)
  case bits
  when 256 then encrypt_v5(user_password, owner_password || user_password, permissions)
  when 128 then encrypt_rc4(user_password, owner_password || user_password,
                            permissions, v: 4, r: 4, length: 128)
  when 40 then encrypt_rc4(user_password, owner_password || user_password,
                           permissions, v: 2, r: 3, length: 40)
  else
    raise Pdfrb::EncryptionError,
          "unsupported key length: #{bits} (use 40, 128, or 256)"
  end
end

#encrypted?Boolean

Whether the document has an /Encrypt dict in the trailer.

Returns:

  • (Boolean)


63
64
65
66
# File 'lib/pdfrb/document/encryption.rb', line 63

def encrypted?
  trailer = document.trailer
  !trailer.nil? && !trailer[:Encrypt].nil?
end