Module: Prawn::Document::Security
- Included in:
- Prawn::Document
- Defined in:
- lib/prawn/security.rb
Overview
Implements PDF encryption (password protection and permissions) as specified in the PDF Reference, version 1.3, section 3.5 “Encryption”.
Experimental API collapse
-
.encrypt_string(str, key, id, gen) ⇒ String
Encrypts the given string under the given key, also requiring the object ID and generation number of the reference.
-
#encrypt_document(options = {}) ⇒ void
Encrypts the document, to protect confidential data or control modifications to the document.
Class Method Details
.encrypt_string(str, key, id, gen) ⇒ String
Encrypts the given string under the given key, also requiring the object ID and generation number of the reference.
See Algorithm 3.1.
Source Code
106 | def self.encrypt_string(str, key, id, gen) |
107 | # Convert ID and Gen number into little-endian truncated byte strings
|
108 | id = [id].pack('V')[0, 3] |
109 | gen = [gen].pack('V')[0, 2] |
110 | extended_key = "#{key}#{id}#{gen}" |
111 | |
112 | # Compute the RC4 key from the extended key and perform the encryption
|
113 | rc4_key = Digest::MD5.digest(extended_key)[0, 10] |
114 | Arcfour.new(rc4_key).encrypt(str) |
115 | end
|
Instance Method Details
#encrypt_document(options = {}) ⇒ void
This method returns an undefined value.
Encrypts the document, to protect confidential data or control modifications to the document. The encryption algorithm used is detailed in the PDF Reference 1.3, section 3.5 “Encryption”, and it is implemented by all major PDF readers.
Examples
Deny printing to everyone, but allow anyone to open without a password:
encrypt_document permissions: { print_document: false },
owner_password: :random
Set a user and owner password on the document, with full permissions for both the user and the owner:
encrypt_document user_password: 'foo', owner_password: 'bar'
Set no passwords, grant all permissions (This is useful because the default in some readers, if no permissions are specified, is “deny”):
encrypt_document
Caveats
- The encryption used is weak; the key is password-derived and is limited to 40 bits, due to US export controls in effect at the time the PDF standard was written.
- There is nothing technologically requiring PDF readers to respect the permissions embedded in a document. Many PDF readers do not.
- In short, you have no security at all against a moderately motivated person. Don’t use this for anything super-serious. This is not a limitation of Prawn, but is rather a built-in limitation of the PDF format.
Source Code
78 | def encrypt_document(options = {}) |
79 | Prawn.verify_options(%i[user_password owner_password permissions], options) |
80 | @user_password = options.delete(:user_password) || '' |
81 | |
82 | @owner_password = options.delete(:owner_password) || @user_password |
83 | if @owner_password == :random |
84 | # Generate a completely ridiculous password
|
85 | @owner_password = (1..32).map { rand(256) }.pack('c*') |
86 | end
|
87 | |
88 | self.permissions = options.delete(:permissions) || {} |
89 | |
90 | # Shove the necessary entries in the trailer and enable encryption.
|
91 | state.trailer[:Encrypt] = encryption_dictionary |
92 | state.encrypt = true |
93 | state.encryption_key = user_encryption_key |
94 | end
|