origami 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,1404 +1,1435 @@
1
1
  =begin
2
2
 
3
- = File
4
- encryption.rb
5
-
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2010 Guillaume DelugrÈ <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- Origami is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU Lesser General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
15
-
16
- Origami is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
- GNU Lesser General Public License for more details.
20
-
21
- You should have received a copy of the GNU Lesser General Public License
22
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
18
 
24
19
  =end
25
20
 
26
21
  begin
27
- require 'openssl' if Origami::OPTIONS[:use_openssl]
22
+ require 'openssl' if Origami::OPTIONS[:use_openssl]
28
23
  rescue LoadError
29
- Origami::OPTIONS[:use_openssl] = false
24
+ Origami::OPTIONS[:use_openssl] = false
30
25
  end
31
26
 
27
+ require 'securerandom'
32
28
  require 'digest/md5'
33
29
  require 'digest/sha2'
34
30
 
35
31
  module Origami
36
32
 
37
- class EncryptionError < Exception #:nodoc:
38
- end
39
-
40
- class EncryptionInvalidPasswordError < EncryptionError #:nodoc:
41
- end
33
+ class EncryptionError < Error #:nodoc:
34
+ end
42
35
 
43
- class EncryptionNotSupportedError < EncryptionError #:nodoc:
44
- end
36
+ class EncryptionInvalidPasswordError < EncryptionError #:nodoc:
37
+ end
45
38
 
46
- class PDF
47
-
48
- #
49
- # Returns whether the PDF file is encrypted.
50
- #
51
- def is_encrypted?
52
- has_attr? :Encrypt
39
+ class EncryptionNotSupportedError < EncryptionError #:nodoc:
53
40
  end
54
-
55
- #
56
- # Decrypts the current document (only RC4 40..128 bits).
57
- # _passwd_:: The password to decrypt the document.
58
- #
59
- def decrypt(passwd = "")
60
-
61
- unless self.is_encrypted?
62
- raise EncryptionError, "PDF is not encrypted"
63
- end
64
-
65
- encrypt_dict = get_doc_attr(:Encrypt)
66
- handler = Encryption::Standard::Dictionary.new(encrypt_dict.dup)
67
-
68
- unless handler.Filter == :Standard
69
- raise EncryptionNotSupportedError, "Unknown security handler : '#{handler.Filter.to_s}'"
70
- end
71
-
72
- case handler.V.to_i
73
- when 1,2 then str_algo = stm_algo = Encryption::ARC4
74
- when 4,5
75
- if handler[:CF].is_a?(Dictionary)
76
- cfs = handler[:CF]
77
-
78
- if handler[:StrF].is_a?(Name) and cfs[handler[:StrF]].is_a?(Dictionary)
79
- cfdict = cfs[handler[:StrF]]
80
-
81
- str_algo =
82
- if cfdict[:CFM] == :V2 then Encryption::ARC4
83
- elsif cfdict[:CFM] == :AESV2 then Encryption::AES
84
- elsif cfdict[:CFM] == :None then Encryption::Identity
85
- elsif cfdict[:CFM] == :AESV3 and handler.V.to_i == 5 then Encryption::AES
86
- else
87
- raise EncryptionNotSupportedError, "Unsupported encryption version : #{handler.V}"
41
+
42
+ class PDF
43
+
44
+ #
45
+ # Returns whether the PDF file is encrypted.
46
+ #
47
+ def encrypted?
48
+ trailer_key? :Encrypt
49
+ end
50
+
51
+ #
52
+ # Decrypts the current document (only RC4 40..128 bits).
53
+ # _passwd_:: The password to decrypt the document.
54
+ #
55
+ def decrypt(passwd = "")
56
+ raise EncryptionError, "PDF is not encrypted" unless self.encrypted?
57
+
58
+ encrypt_dict = trailer_key(:Encrypt)
59
+ handler = Encryption::Standard::Dictionary.new(encrypt_dict.dup)
60
+
61
+ unless handler.Filter == :Standard
62
+ raise EncryptionNotSupportedError, "Unknown security handler : '#{handler.Filter.to_s}'"
63
+ end
64
+
65
+ crypt_filters = {
66
+ Identity: Encryption::Identity
67
+ }
68
+
69
+ case handler.V.to_i
70
+ when 1,2
71
+ crypt_filters = Hash.new(Encryption::RC4)
72
+ string_filter = stream_filter = nil
73
+ when 4,5
74
+ crypt_filters = {
75
+ Identity: Encryption::Identity
76
+ }
77
+
78
+ if handler[:CF].is_a?(Dictionary)
79
+ handler[:CF].each_pair do |name, cf|
80
+ next unless cf.is_a?(Dictionary)
81
+
82
+ crypt_filters[name.value] =
83
+ if cf[:CFM] == :V2 then Encryption::RC4
84
+ elsif cf[:CFM] == :AESV2 then Encryption::AES
85
+ elsif cf[:CFM] == :None then Encryption::Identity
86
+ elsif cf[:CFM] == :AESV3 and handler.V.to_i == 5 then Encryption::AES
87
+ else
88
+ raise EncryptionNotSupportedError, "Unsupported encryption version : #{handler.V}"
89
+ end
90
+ end
91
+ end
92
+
93
+ string_filter = handler.StrF.is_a?(Name) ? handler.StrF.value : :Identity
94
+ stream_filter = handler.StmF.is_a?(Name) ? handler.StmF.value : :Identity
95
+
96
+ unless crypt_filters.key?(string_filter)
97
+ raise EncryptionError, "Invalid StrF value in encryption dictionary"
98
+ end
99
+
100
+ unless crypt_filters.key?(stream_filter)
101
+ raise EncryptionError, "Invalid StmF value in encryption dictionary"
88
102
  end
89
103
  else
90
- str_algo = Encryption::Identity
104
+ raise EncryptionNotSupportedError, "Unsupported encryption version : #{handler.V}"
91
105
  end
92
106
 
93
- if handler[:StmF].is_a?(Name) and cfs[handler[:StmF]].is_a?(Dictionary)
94
- cfdict = cfs[handler[:StmF]]
107
+ doc_id = trailer_key(:ID)
108
+ unless doc_id.is_a?(Array)
109
+ raise EncryptionError, "Document ID was not found or is invalid" unless handler.V.to_i == 5
110
+ else
111
+ doc_id = doc_id.first
112
+ end
95
113
 
96
- stm_algo =
97
- if cfdict[:CFM] == :V2 then Encryption::ARC4
98
- elsif cfdict[:CFM] == :AESV2 then Encryption::AES
99
- elsif cfdict[:CFM] == :None then Encryption::Identity
100
- elsif cfdict[:CFM] == :AESV3 and handler.V.to_i == 5 then Encryption::AES
114
+ if handler.is_user_password?(passwd, doc_id)
115
+ encryption_key = handler.compute_user_encryption_key(passwd, doc_id)
116
+ elsif handler.is_owner_password?(passwd, doc_id)
117
+ if handler.V.to_i < 5
118
+ user_passwd = handler.retrieve_user_password(passwd)
119
+ encryption_key = handler.compute_user_encryption_key(user_passwd, doc_id)
101
120
  else
102
- raise EncryptionNotSupportedError, "Unsupported encryption version : #{handler.V}"
121
+ encryption_key = handler.compute_owner_encryption_key(passwd)
103
122
  end
104
123
  else
105
- stm_algo = Encryption::Identity
124
+ raise EncryptionInvalidPasswordError
106
125
  end
107
126
 
108
- else
109
- str_algo = stm_algo = Encryption::Identity
110
- end
111
-
112
- else
113
- raise EncryptionNotSupportedError, "Unsupported encryption version : #{handler.V}"
114
- end
115
-
116
- doc_id = get_doc_attr(:ID)
117
- unless doc_id.is_a?(Array)
118
- raise EncryptionError, "Document ID was not found or is invalid" unless handler.V.to_i == 5
119
- else
120
- doc_id = doc_id.first
121
- end
122
-
123
- if handler.is_user_password?(passwd, doc_id)
124
- encryption_key = handler.compute_user_encryption_key(passwd, doc_id)
125
- elsif handler.is_owner_password?(passwd, doc_id)
126
- if handler.V.to_i < 5
127
- user_passwd = handler.retrieve_user_password(passwd)
128
- encryption_key = handler.compute_user_encryption_key(user_passwd, doc_id)
129
- else
130
- encryption_key = handler.compute_owner_encryption_key(passwd)
131
- end
132
- else
133
- raise EncryptionInvalidPasswordError
134
- end
135
-
136
-
137
- #self.extend(Encryption::EncryptedDocument)
138
- #self.encryption_dict = encrypt_dict
139
- #self.encryption_key = encryption_key
140
- #self.stm_algo = self.str_algo = algorithm
141
-
142
- encrypt_metadata = (handler.EncryptMetadata != false)
143
-
144
- self.extend(Encryption::EncryptedDocument)
145
- self.encryption_dict = handler
146
- self.encryption_key = encryption_key
147
- self.stm_algo,self.str_algo = stm_algo,str_algo
148
-
149
- #
150
- # Should be fixed to exclude only the active XRefStream
151
- #
152
- metadata = self.Catalog.Metadata
153
-
154
- self.indirect_objects.each do |indobj|
155
- encrypted_objects = []
156
- case indobj
157
- when String,Stream then encrypted_objects << indobj
158
- when Dictionary,Array then encrypted_objects |= indobj.strings_cache
159
- end
127
+ encrypt_metadata = (handler.EncryptMetadata != false)
160
128
 
161
- encrypted_objects.each do |obj|
162
-
163
- case obj
164
- when String
165
- next if obj.equal?(encrypt_dict[:U]) or
166
- obj.equal?(encrypt_dict[:O]) or
167
- obj.equal?(encrypt_dict[:UE]) or
168
- obj.equal?(encrypt_dict[:OE]) or
169
- obj.equal?(encrypt_dict[:Perms]) or
170
- (obj.parent.is_a?(Signature::DigitalSignature) and obj.equal?(obj.parent[:Contents]))
171
-
172
- obj.extend(Encryption::EncryptedString) unless obj.is_a?(Encryption::EncryptedString)
173
- obj.encryption_handler = handler
174
- obj.encryption_key = encryption_key
175
- obj.algorithm = str_algo
176
- obj.decrypt!
177
-
178
- when Stream
179
- next if obj.is_a?(XRefStream) or (not encrypt_metadata and obj.equal?(metadata))
180
- obj.extend(Encryption::EncryptedStream) unless obj.is_a?(Encryption::EncryptedStream)
181
- obj.encryption_handler = handler
182
- obj.encryption_key = encryption_key
183
- obj.algorithm = stm_algo
184
- end
185
- end
186
- end
129
+ self.extend(Encryption::EncryptedDocument)
130
+ self.encryption_handler = handler
131
+ self.crypt_filters = crypt_filters
132
+ self.encryption_key = encryption_key
133
+ self.stm_filter, self.str_filter = stream_filter, string_filter
187
134
 
188
- self
189
- end
190
-
191
- #
192
- # Encrypts the current document with the provided passwords.
193
- # The document will be encrypted at writing-on-disk time.
194
- # _userpasswd_:: The user password.
195
- # _ownerpasswd_:: The owner password.
196
- # _options_:: A set of options to configure encryption.
197
- #
198
- def encrypt(options = {})
199
-
200
- if self.is_encrypted?
201
- raise EncryptionError, "PDF is already encrypted"
202
- end
203
-
204
- #
205
- # Default encryption options.
206
- #
207
- params =
208
- {
209
- :user_passwd => '',
210
- :owner_passwd => '',
211
- :cipher => 'rc4', # :RC4 or :AES
212
- :key_size => 128, # Key size in bits
213
- :hardened => false, # Use newer password validation (since Reader X)
214
- :encrypt_metadata => true, # Metadata shall be encrypted?
215
- :permissions => Encryption::Standard::Permissions::ALL # Document permissions
216
- }.update(options)
217
-
218
- userpasswd, ownerpasswd = params[:user_passwd], params[:owner_passwd]
219
-
220
- case params[:cipher].upcase
221
- when 'RC4'
222
- algorithm = Encryption::ARC4
223
- if (40..128) === params[:key_size] and params[:key_size] % 8 == 0
224
- if params[:key_size] > 40
225
- version = 2
226
- revision = 3
227
- else
228
- version = 1
229
- revision = 2
135
+ #
136
+ # Should be fixed to exclude only the active XRefStream
137
+ #
138
+ metadata = self.Catalog.Metadata
139
+
140
+ self.indirect_objects.each do |indobj|
141
+ encrypted_objects = []
142
+ case indobj
143
+ when String,Stream then encrypted_objects << indobj
144
+ when Dictionary,Array then encrypted_objects |= indobj.strings_cache
145
+ end
146
+
147
+ encrypted_objects.each do |obj|
148
+ case obj
149
+ when String
150
+ next if obj.equal?(encrypt_dict[:U]) or
151
+ obj.equal?(encrypt_dict[:O]) or
152
+ obj.equal?(encrypt_dict[:UE]) or
153
+ obj.equal?(encrypt_dict[:OE]) or
154
+ obj.equal?(encrypt_dict[:Perms]) or
155
+ (obj.parent.is_a?(Signature::DigitalSignature) and
156
+ obj.equal?(obj.parent[:Contents]))
157
+
158
+ obj.extend(Encryption::EncryptedString) unless obj.is_a?(Encryption::EncryptedString)
159
+ obj.decrypt!
160
+
161
+ when Stream
162
+ next if obj.is_a?(XRefStream) or (not encrypt_metadata and obj.equal?(metadata))
163
+
164
+ obj.extend(Encryption::EncryptedStream) unless obj.is_a?(Encryption::EncryptedStream)
165
+ end
166
+ end
230
167
  end
231
- else
232
- raise EncryptionError, "Invalid RC4 key length"
233
- end
234
- when 'AES'
235
- algorithm = Encryption::AES
236
- if params[:key_size] == 128
237
- version = revision = 4
238
- elsif params[:key_size] == 256
239
- version = 5
240
- if params[:hardened]
241
- revision = 6
168
+
169
+ self
170
+ end
171
+
172
+ #
173
+ # Encrypts the current document with the provided passwords.
174
+ # The document will be encrypted at writing-on-disk time.
175
+ # _userpasswd_:: The user password.
176
+ # _ownerpasswd_:: The owner password.
177
+ # _options_:: A set of options to configure encryption.
178
+ #
179
+ def encrypt(options = {})
180
+ raise EncryptionError, "PDF is already encrypted" if self.encrypted?
181
+
182
+ #
183
+ # Default encryption options.
184
+ #
185
+ params =
186
+ {
187
+ :user_passwd => '',
188
+ :owner_passwd => '',
189
+ :cipher => 'rc4', # :RC4 or :AES
190
+ :key_size => 128, # Key size in bits
191
+ :hardened => false, # Use newer password validation (since Reader X)
192
+ :encrypt_metadata => true, # Metadata shall be encrypted?
193
+ :permissions => Encryption::Standard::Permissions::ALL # Document permissions
194
+ }.update(options)
195
+
196
+ userpasswd, ownerpasswd = params[:user_passwd], params[:owner_passwd]
197
+
198
+ case params[:cipher].upcase
199
+ when 'RC4'
200
+ algorithm = Encryption::RC4
201
+ if (40..128) === params[:key_size] and params[:key_size] % 8 == 0
202
+ if params[:key_size] > 40
203
+ version = 2
204
+ revision = 3
205
+ else
206
+ version = 1
207
+ revision = 2
208
+ end
209
+ else
210
+ raise EncryptionError, "Invalid RC4 key length"
211
+ end
212
+
213
+ crypt_filters = Hash.new(algorithm)
214
+ string_filter = stream_filter = nil
215
+
216
+ when 'AES'
217
+ algorithm = Encryption::AES
218
+ if params[:key_size] == 128
219
+ version = revision = 4
220
+ elsif params[:key_size] == 256
221
+ version = 5
222
+ if params[:hardened]
223
+ revision = 6
224
+ else
225
+ revision = 5
226
+ end
227
+ else
228
+ raise EncryptionError, "Invalid AES key length (Only 128 and 256 bits keys are supported)"
229
+ end
230
+
231
+ crypt_filters = {
232
+ Identity: Encryption::Identity,
233
+ StdCF: algorithm
234
+ }
235
+ string_filter = stream_filter = :StdCF
236
+
242
237
  else
243
- revision = 5
238
+ raise EncryptionNotSupportedError, "Cipher not supported : #{params[:cipher]}"
244
239
  end
245
- else
246
- raise EncryptionError, "Invalid AES key length (Only 128 and 256 bits keys are supported)"
247
- end
248
- else
249
- raise EncryptionNotSupportedError, "Cipher not supported : #{params[:cipher]}"
250
- end
251
-
252
- doc_id = (get_doc_attr(:ID) || gen_id).first
253
-
254
- handler = Encryption::Standard::Dictionary.new
255
- handler.Filter = :Standard #:nodoc:
256
- handler.V = version
257
- handler.R = revision
258
- handler.Length = params[:key_size]
259
- handler.P = -1 # params[:Permissions]
260
-
261
- if revision >= 4
262
- handler.EncryptMetadata = params[:encrypt_metadata]
263
- handler.CF = Dictionary.new
264
- cryptfilter = Encryption::CryptFilterDictionary.new
265
- cryptfilter.AuthEvent = :DocOpen
266
-
267
- if revision == 4
268
- cryptfilter.CFM = :AESV2
269
- else
270
- cryptfilter.CFM = :AESV3
271
- end
272
240
 
273
- cryptfilter.Length = params[:key_size] >> 3
241
+ doc_id = (trailer_key(:ID) || generate_id).first
274
242
 
275
- handler.CF[:StdCF] = cryptfilter
276
- handler.StmF = handler.StrF = :StdCF
277
- end
278
-
279
- handler.set_passwords(ownerpasswd, userpasswd, doc_id)
280
- encryption_key = handler.compute_user_encryption_key(userpasswd, doc_id)
243
+ handler = Encryption::Standard::Dictionary.new
244
+ handler.Filter = :Standard #:nodoc:
245
+ handler.V = version
246
+ handler.R = revision
247
+ handler.Length = params[:key_size]
248
+ handler.P = -1 # params[:Permissions]
281
249
 
282
- fileInfo = get_trailer_info
283
- fileInfo[:Encrypt] = self << handler
250
+ if revision >= 4
251
+ handler.EncryptMetadata = params[:encrypt_metadata]
252
+ handler.CF = Dictionary.new
253
+ cryptfilter = Encryption::CryptFilterDictionary.new
254
+ cryptfilter.AuthEvent = :DocOpen
284
255
 
285
- self.extend(Encryption::EncryptedDocument)
286
- self.encryption_dict = handler
287
- self.encryption_key = encryption_key
288
- self.stm_algo = self.str_algo = algorithm
256
+ if revision == 4
257
+ cryptfilter.CFM = :AESV2
258
+ else
259
+ cryptfilter.CFM = :AESV3
260
+ end
289
261
 
290
- self
291
- end
292
-
293
- end
262
+ cryptfilter.Length = params[:key_size] >> 3
263
+
264
+ handler.CF[:StdCF] = cryptfilter
265
+ handler.StmF = handler.StrF = :StdCF
266
+ end
294
267
 
295
- #
296
- # Module to provide support for encrypting and decrypting PDF documents.
297
- #
298
- module Encryption
268
+ handler.set_passwords(ownerpasswd, userpasswd, doc_id)
269
+ encryption_key = handler.compute_user_encryption_key(userpasswd, doc_id)
299
270
 
300
- #
301
- # Generates _n_ random bytes from a fast PRNG.
302
- #
303
- def self.rand_bytes(n)
304
- ::Array.new(n) { rand(256) }.pack("C*")
271
+ file_info = get_trailer_info
272
+ file_info[:Encrypt] = self << handler
273
+
274
+ self.extend(Encryption::EncryptedDocument)
275
+ self.encryption_handler = handler
276
+ self.encryption_key = encryption_key
277
+ self.crypt_filters = crypt_filters
278
+ self.stm_filter = self.str_filter = :StdCF
279
+
280
+ self
281
+ end
305
282
  end
306
283
 
307
284
  #
308
- # Generates _n_ random bytes from a crypto PRNG.
285
+ # Module to provide support for encrypting and decrypting PDF documents.
309
286
  #
310
- def self.strong_rand_bytes(n)
311
- if Origami::OPTIONS[:use_openssl]
312
- OpenSSL::Random.random_bytes(n)
313
- elsif RUBY_VERSION >= '1.9'
314
- Random.new.bytes(n)
315
- else
316
- self.rand_bytes(n)
317
- end
318
- end
319
-
320
- module EncryptedDocument
287
+ module Encryption
321
288
 
322
- attr_writer :encryption_key
323
- attr_writer :encryption_dict
324
- attr_writer :stm_algo
325
- attr_writer :str_algo
289
+ #
290
+ # Generates _n_ random bytes from a fast PRNG.
291
+ #
292
+ def self.rand_bytes(n)
293
+ Random.new.bytes(n)
294
+ end
326
295
 
327
- private
296
+ #
297
+ # Generates _n_ random bytes from a crypto PRNG.
298
+ #
299
+ def self.strong_rand_bytes(n)
300
+ if Origami::OPTIONS[:use_openssl]
301
+ OpenSSL::Random.random_bytes(n)
302
+ else
303
+ SecureRandom.random_bytes(n)
304
+ end
305
+ end
328
306
 
329
- def physicalize(options = {})
307
+ module EncryptedDocument
308
+ attr_accessor :encryption_key
309
+ attr_accessor :encryption_handler
310
+ attr_accessor :str_filter, :stm_filter
311
+ attr_accessor :crypt_filters
330
312
 
331
- def build(obj, revision, options) #:nodoc:
332
- if obj.is_a?(EncryptedObject) # already built
333
- if options[:decrypt] == true
334
- obj.pre_build
335
- obj.decrypt!
336
- obj.decrypted = false # makes it believe no encryption pass is required
337
- obj.post_build
313
+ # Get the encryption cipher from the crypt filter name.
314
+ def encryption_cipher(name)
315
+ @crypt_filters[name]
338
316
  end
339
317
 
340
- return
341
- end
342
-
343
- if obj.is_a?(ObjectStream)
344
- obj.each do |subobj|
345
- build(subobj, revision, options)
318
+ # Get the default string encryption cipher.
319
+ def string_encryption_cipher
320
+ encryption_cipher @str_filter
346
321
  end
347
- end
348
-
349
- obj.pre_build
350
-
351
- case obj
352
- when String
353
- if not obj.equal?(@encryption_dict[:U]) and
354
- not obj.equal?(@encryption_dict[:O]) and
355
- not obj.equal?(@encryption_dict[:UE]) and
356
- not obj.equal?(@encryption_dict[:OE]) and
357
- not obj.equal?(@encryption_dict[:Perms]) and
358
- not (obj.parent.is_a?(Signature::DigitalSignature) and obj.equal?(obj.parent[:Contents])) and
359
- not obj.indirect_parent.parent.is_a?(ObjectStream)
360
-
361
- obj.extend(EncryptedString)
362
- obj.decrypted = true
363
- obj.encryption_handler = @encryption_dict
364
- obj.encryption_key = @encryption_key
365
- obj.algorithm = @str_algo
322
+
323
+ # Get the default stream encryption cipher.
324
+ def stream_encryption_cipher
325
+ encryption_cipher @stm_filter
366
326
  end
367
327
 
368
- when Stream
369
- return if obj.is_a?(XRefStream)
370
- return if obj.equal?(self.Catalog.Metadata) and not @encryption_dict.EncryptMetadata
371
- obj.extend(EncryptedStream)
372
- obj.decrypted = true
373
- obj.encryption_handler = @encryption_dict
374
- obj.encryption_key = @encryption_key
375
- obj.algorithm = @stm_algo
376
-
377
- when Dictionary, Array
378
- obj.map! do |subobj|
379
- if subobj.is_indirect?
380
- if get_object(subobj.reference)
381
- subobj.reference
382
- else
383
- ref = add_to_revision(subobj, revision)
384
- build(subobj, revision, options)
385
- ref
328
+ private
329
+
330
+ def physicalize(options = {})
331
+
332
+ build = -> (obj, revision) do
333
+ if obj.is_a?(EncryptedObject)
334
+ if options[:decrypt] == true
335
+ obj.pre_build
336
+ obj.decrypt!
337
+ obj.decrypted = false # makes it believe no encryption pass is required
338
+ obj.post_build
339
+
340
+ return
341
+ end
342
+ end
343
+
344
+ if obj.is_a?(ObjectStream)
345
+ obj.each do |subobj|
346
+ build.call(subobj, revision)
347
+ end
348
+ end
349
+
350
+ obj.pre_build
351
+
352
+ case obj
353
+ when String
354
+ if not obj.equal?(@encryption_handler[:U]) and
355
+ not obj.equal?(@encryption_handler[:O]) and
356
+ not obj.equal?(@encryption_handler[:UE]) and
357
+ not obj.equal?(@encryption_handler[:OE]) and
358
+ not obj.equal?(@encryption_handler[:Perms]) and
359
+ not (obj.parent.is_a?(Signature::DigitalSignature) and
360
+ obj.equal?(obj.parent[:Contents])) and
361
+ not obj.indirect_parent.parent.is_a?(ObjectStream)
362
+
363
+ unless obj.is_a?(EncryptedString)
364
+ obj.extend(EncryptedString)
365
+ obj.decrypted = true
366
+ end
367
+ end
368
+
369
+ when Stream
370
+ return if obj.is_a?(XRefStream)
371
+ return if obj.equal?(self.Catalog.Metadata) and not @encryption_handler.EncryptMetadata
372
+
373
+ unless obj.is_a?(EncryptedStream)
374
+ obj.extend(EncryptedStream)
375
+ obj.decrypted = true
376
+ end
377
+
378
+ when Dictionary, Array
379
+ obj.map! do |subobj|
380
+ if subobj.indirect?
381
+ if get_object(subobj.reference)
382
+ subobj.reference
383
+ else
384
+ ref = add_to_revision(subobj, revision)
385
+ build.call(subobj, revision)
386
+ ref
387
+ end
388
+ else
389
+ subobj
390
+ end
391
+ end
392
+
393
+ obj.each do |subobj|
394
+ build.call(subobj, revision)
395
+ end
396
+ end
397
+
398
+ obj.post_build
399
+ end
400
+
401
+ # stack up every root objects
402
+ indirect_objects_by_rev.each do |obj, revision|
403
+ build.call(obj, revision)
404
+ end
405
+
406
+ # remove encrypt dictionary if requested
407
+ if options[:decrypt]
408
+ delete_object(get_trailer_info[:Encrypt])
409
+ get_trailer_info[:Encrypt] = nil
386
410
  end
387
- else
388
- subobj
389
- end
411
+
412
+ self
390
413
  end
391
-
392
- obj.each do |subobj|
393
- build(subobj, revision, options)
414
+ end
415
+
416
+ #
417
+ # Module for encrypted PDF objects.
418
+ #
419
+ module EncryptedObject #:nodoc
420
+ attr_accessor :decrypted
421
+
422
+ def post_build
423
+ encrypt!
424
+
425
+ super
394
426
  end
395
- end
396
427
 
397
- obj.post_build
398
- end
399
-
400
- # stack up every root objects
401
- indirect_objects_by_rev.each do |obj, revision|
402
- build(obj, revision, options)
403
- end
428
+ private
404
429
 
405
- # remove encrypt dictionary if requested
406
- if options[:decrypt]
407
- delete_object(get_trailer_info[:Encrypt])
408
- get_trailer_info[:Encrypt] = nil
409
- end
410
-
411
- self
412
- end
413
-
414
- end
430
+ def compute_object_key(cipher)
431
+ doc = self.document
432
+ raise EncryptionError, "Document is not encrypted" unless doc.is_a?(EncryptedDocument)
415
433
 
416
- #
417
- # Module for encrypted PDF objects.
418
- #
419
- module EncryptedObject #:nodoc
420
-
421
- attr_writer :encryption_key
422
- attr_writer :algorithm
423
- attr_writer :encryption_handler
424
- attr_accessor :decrypted
425
-
426
- def self.extended(obj)
427
- obj.decrypted = false
428
- end
429
-
430
- def post_build
431
- encrypt!
432
-
433
- super
434
- end
435
-
436
- private
437
-
438
- def compute_object_key
439
- if @encryption_handler.V < 5
440
- parent = self.indirect_parent
441
- no, gen = parent.no, parent.generation
442
- k = @encryption_key + [no].pack("I")[0..2] + [gen].pack("I")[0..1]
443
-
444
- key_len = (k.length > 16) ? 16 : k.length
445
- k << "sAlT" if @algorithm == Encryption::AES
446
-
447
- Digest::MD5.digest(k)[0, key_len]
448
- else
449
- @encryption_key
450
- end
451
- end
434
+ encryption_key = doc.encryption_key
452
435
 
453
- end
436
+ if doc.encryption_handler.V < 5
437
+ parent = self.indirect_parent
438
+ no, gen = parent.no, parent.generation
439
+ k = encryption_key + [no].pack("I")[0..2] + [gen].pack("I")[0..1]
454
440
 
455
- #
456
- # Module for encrypted String.
457
- #
458
- module EncryptedString
459
- include EncryptedObject
460
-
461
- def encrypt!
462
- if @decrypted
463
- key = compute_object_key
464
-
465
- encrypted_data =
466
- if @algorithm == ARC4 or @algorithm == Identity
467
- @algorithm.encrypt(key, self.value)
468
- else
469
- iv = Encryption.rand_bytes(AES::BLOCKSIZE)
470
- @algorithm.encrypt(key, iv, self.value)
471
- end
472
-
473
- @decrypted = false
474
-
475
- self.replace(encrypted_data)
476
- self.freeze
477
- end
478
-
479
- self
480
- end
481
-
482
- def decrypt!
483
- unless @decrypted
484
- key = compute_object_key
485
- self.replace(@algorithm.decrypt(key, self.to_str))
486
- @decrypted = true
441
+ key_len = (k.length > 16) ? 16 : k.length
442
+ k << "sAlT" if cipher == Encryption::AES
443
+
444
+ Digest::MD5.digest(k)[0, key_len]
445
+ else
446
+ encryption_key
447
+ end
448
+ end
487
449
  end
488
450
 
489
- self
490
- end
491
- end
451
+ #
452
+ # Module for encrypted String.
453
+ #
454
+ module EncryptedString
455
+ include EncryptedObject
492
456
 
493
- #
494
- # Module for encrypted Stream.
495
- #
496
- module EncryptedStream
497
- include EncryptedObject
457
+ def self.extended(obj)
458
+ obj.decrypted = false
459
+ end
498
460
 
499
- def encrypt!
500
- if @decrypted
501
- encode!
461
+ def encrypt!
462
+ return self unless @decrypted
502
463
 
503
- key = compute_object_key
464
+ cipher = self.document.string_encryption_cipher
465
+ raise EncryptionError, "Cannot find string encryption filter" if cipher.nil?
504
466
 
505
- @rawdata =
506
- if @algorithm == ARC4 or @algorithm == Identity
507
- @algorithm.encrypt(key, self.rawdata)
508
- else
509
- iv = Encryption.rand_bytes(AES::BLOCKSIZE)
510
- @algorithm.encrypt(key, iv, @rawdata)
467
+ key = compute_object_key(cipher)
468
+
469
+ encrypted_data =
470
+ if cipher == RC4 or cipher == Identity
471
+ cipher.encrypt(key, self.value)
472
+ else
473
+ iv = Encryption.rand_bytes(AES::BLOCKSIZE)
474
+ cipher.encrypt(key, iv, self.value)
475
+ end
476
+
477
+ @decrypted = false
478
+
479
+ self.replace(encrypted_data)
480
+ self.freeze
481
+
482
+ self
511
483
  end
512
484
 
513
- @decrypted = false
485
+ def decrypt!
486
+ return self if @decrypted
514
487
 
515
- @rawdata.freeze
516
- self.freeze
517
- end
488
+ cipher = self.document.string_encryption_cipher
489
+ raise EncryptionError, "Cannot find string encryption filter" if cipher.nil?
518
490
 
519
- self
520
- end
491
+ key = compute_object_key(cipher)
521
492
 
522
- def decrypt!
523
- unless @decrypted
524
- key = compute_object_key
493
+ self.replace(cipher.decrypt(key, self.to_str))
494
+ @decrypted = true
525
495
 
526
- self.rawdata = @algorithm.decrypt(key, @rawdata)
527
- @decrypted = true
496
+ self
497
+ end
528
498
  end
529
499
 
530
- self
531
- end
500
+ #
501
+ # Module for encrypted Stream.
502
+ #
503
+ module EncryptedStream
504
+ include EncryptedObject
532
505
 
533
- end
506
+ def self.extended(obj)
507
+ obj.decrypted = false
508
+ end
534
509
 
535
- #
536
- # Identity transformation.
537
- #
538
- module Identity
539
- def Identity.encrypt(key, data)
540
- data
541
- end
542
-
543
- def Identity.decrypt(key, data)
544
- data
545
- end
546
- end
510
+ def encrypt!
511
+ return self unless @decrypted
547
512
 
548
- #
549
- # Pure Ruby implementation of the aRC4 symmetric algorithm
550
- #
551
- class ARC4
552
-
553
- #
554
- # Encrypts data using the given key
555
- #
556
- def ARC4.encrypt(key, data)
557
- ARC4.new(key).encrypt(data)
558
- end
559
-
560
- #
561
- # Decrypts data using the given key
562
- #
563
- def ARC4.decrypt(key, data)
564
- ARC4.new(key).decrypt(data)
565
- end
566
-
567
- #
568
- # Creates and initialises a new aRC4 generator using given key
569
- #
570
- def initialize(key)
571
- if Origami::OPTIONS[:use_openssl]
572
- @key = key
573
- else
574
- @state = init(key)
575
- end
576
- end
577
-
578
- #
579
- # Encrypt/decrypt data with the aRC4 encryption algorithm
580
- #
581
- def cipher(data)
582
- return "" if data.empty?
583
-
584
- if Origami::OPTIONS[:use_openssl]
585
- rc4 = OpenSSL::Cipher::RC4.new.encrypt
586
- rc4.key_len = @key.length
587
- rc4.key = @key
588
-
589
- output = rc4.update(data) << rc4.final
590
- else
591
- output = ""
592
- i, j = 0, 0
593
- data.each_byte do |byte|
594
- i = i.succ & 0xFF
595
- j = (j + @state[i]) & 0xFF
596
-
597
- @state[i], @state[j] = @state[j], @state[i]
598
-
599
- output << (@state[@state[i] + @state[j] & 0xFF] ^ byte).chr
600
- end
601
- end
602
-
603
- output
604
- end
605
-
606
- alias encrypt cipher
607
- alias decrypt cipher
608
-
609
- private
610
-
611
- def init(key) #:nodoc:
612
-
613
- state = (0..255).to_a
614
-
615
- j = 0
616
- 256.times do |i|
617
- j = ( j + state[i] + key[i % key.size].ord ) & 0xFF
618
- state[i], state[j] = state[j], state[i]
619
- end
620
-
621
- state
622
- end
513
+ encode!
623
514
 
624
- end
515
+ if self.filters.first == :Crypt
516
+ params = decode_params.first
625
517
 
626
- #
627
- # Pure Ruby implementation of the AES symmetric algorithm.
628
- # Using mode CBC.
629
- #
630
- class AES
631
-
632
- NROWS = 4
633
- NCOLS = 4
634
- BLOCKSIZE = NROWS * NCOLS
635
-
636
- ROUNDS =
637
- {
638
- 16 => 10,
639
- 24 => 12,
640
- 32 => 14
641
- }
642
-
643
- #
644
- # Rijndael S-box
645
- #
646
- SBOX =
647
- [
648
- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
649
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
650
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
651
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
652
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
653
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
654
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
655
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
656
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
657
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
658
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
659
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
660
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
661
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
662
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
663
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
664
- ]
665
-
666
- #
667
- # Inverse of the Rijndael S-box
668
- #
669
- RSBOX =
670
- [
671
- 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
672
- 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
673
- 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
674
- 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
675
- 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
676
- 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
677
- 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
678
- 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
679
- 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
680
- 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
681
- 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
682
- 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
683
- 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
684
- 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
685
- 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
686
- 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
687
- ]
688
-
689
- RCON =
690
- [
691
- 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
692
- 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
693
- 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
694
- 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
695
- 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
696
- 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
697
- 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
698
- 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
699
- 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
700
- 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
701
- 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
702
- 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
703
- 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
704
- 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
705
- 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
706
- 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb
707
- ]
708
-
709
- attr_writer :iv
710
-
711
- def AES.encrypt(key, iv, data)
712
- AES.new(key, iv).encrypt(data)
713
- end
714
-
715
- def AES.decrypt(key, data)
716
- AES.new(key, nil).decrypt(data)
717
- end
718
-
719
- def initialize(key, iv, use_padding = true)
720
- unless key.size == 16 or key.size == 24 or key.size == 32
721
- raise EncryptionError, "Key must have a length of 128, 192 or 256 bits."
722
- end
518
+ if params.is_a?(Dictionary) and params.Name.is_a?(Name)
519
+ crypt_filter = params.Name.value
520
+ else
521
+ crypt_filter = :Identity
522
+ end
723
523
 
724
- if not iv.nil? and iv.size != BLOCKSIZE
725
- raise EncryptionError, "Initialization vector must have a length of #{BLOCKSIZE} bytes."
726
- end
524
+ cipher = self.document.encryption_cipher(crypt_filter)
525
+ else
526
+ cipher = self.document.stream_encryption_cipher
527
+ end
528
+ raise EncryptionError, "Cannot find stream encryption filter" if cipher.nil?
727
529
 
728
- @key = key
729
- @iv = iv
730
- @use_padding = use_padding
731
- end
530
+ key = compute_object_key(cipher)
732
531
 
733
- def encrypt(data)
532
+ @encoded_data =
533
+ if cipher == RC4 or cipher == Identity
534
+ cipher.encrypt(key, self.encoded_data)
535
+ else
536
+ iv = Encryption.rand_bytes(AES::BLOCKSIZE)
537
+ cipher.encrypt(key, iv, @encoded_data)
538
+ end
539
+
540
+ @decrypted = false
541
+
542
+ @encoded_data.freeze
543
+ self.freeze
544
+
545
+ self
546
+ end
547
+
548
+ def decrypt!
549
+ return self if @decrypted
550
+
551
+ if self.filters.first == :Crypt
552
+ params = decode_params.first
553
+
554
+ if params.is_a?(Dictionary) and params.Name.is_a?(Name)
555
+ crypt_filter = params.Name.value
556
+ else
557
+ crypt_filter = :Identity
558
+ end
559
+
560
+ cipher = self.document.encryption_cipher(crypt_filter)
561
+ else
562
+ cipher = self.document.stream_encryption_cipher
563
+ end
564
+ raise EncryptionError, "Cannot find stream encryption filter" if cipher.nil?
734
565
 
735
- if @iv.nil?
736
- raise EncryptionError, "No initialization vector has been set."
566
+ key = compute_object_key(cipher)
567
+
568
+ self.encoded_data = cipher.decrypt(key, @encoded_data)
569
+ @decrypted = true
570
+
571
+ self
572
+ end
737
573
  end
738
-
739
- if @use_padding
740
- padlen = BLOCKSIZE - (data.size % BLOCKSIZE)
741
- data << (padlen.chr * padlen)
574
+
575
+ #
576
+ # Identity transformation.
577
+ #
578
+ module Identity
579
+ def Identity.encrypt(key, data)
580
+ data
581
+ end
582
+
583
+ def Identity.decrypt(key, data)
584
+ data
585
+ end
742
586
  end
743
587
 
744
- if Origami::OPTIONS[:use_openssl]
745
- aes = OpenSSL::Cipher::Cipher.new("aes-#{@key.length << 3}-cbc").encrypt
746
- aes.iv = @iv
747
- aes.key = @key
748
- aes.padding = 0
588
+ #
589
+ # Pure Ruby implementation of the RC4 symmetric algorithm
590
+ #
591
+ class RC4
749
592
 
750
- @iv + aes.update(data) + aes.final
751
- else
752
- cipher = []
753
- cipherblock = []
754
- nblocks = data.size / BLOCKSIZE
593
+ #
594
+ # Encrypts data using the given key
595
+ #
596
+ def RC4.encrypt(key, data)
597
+ RC4.new(key).encrypt(data)
598
+ end
755
599
 
756
- first_round = true
757
- nblocks.times do |n|
758
- plainblock = data[n * BLOCKSIZE, BLOCKSIZE].unpack("C*")
600
+ #
601
+ # Decrypts data using the given key
602
+ #
603
+ def RC4.decrypt(key, data)
604
+ RC4.new(key).decrypt(data)
605
+ end
759
606
 
760
- if first_round
761
- BLOCKSIZE.times do |i| plainblock[i] ^= @iv[i].ord end
762
- else
763
- BLOCKSIZE.times do |i| plainblock[i] ^= cipherblock[i] end
607
+ #
608
+ # Creates and initialises a new RC4 generator using given key
609
+ #
610
+ def initialize(key)
611
+ if Origami::OPTIONS[:use_openssl]
612
+ @key = key
613
+ else
614
+ @state = init(key)
615
+ end
764
616
  end
765
617
 
766
- first_round = false
767
- cipherblock = aesEncrypt(plainblock)
768
- cipher.concat(cipherblock)
769
- end
618
+ #
619
+ # Encrypt/decrypt data with the RC4 encryption algorithm
620
+ #
621
+ def cipher(data)
622
+ return "" if data.empty?
770
623
 
771
- @iv + cipher.pack("C*")
772
- end
773
- end
624
+ if Origami::OPTIONS[:use_openssl]
625
+ rc4 = OpenSSL::Cipher::RC4.new.encrypt
626
+ rc4.key_len = @key.length
627
+ rc4.key = @key
628
+
629
+ output = rc4.update(data) << rc4.final
630
+ else
631
+ output = ""
632
+ i, j = 0, 0
633
+ data.each_byte do |byte|
634
+ i = i.succ & 0xFF
635
+ j = (j + @state[i]) & 0xFF
636
+
637
+ @state[i], @state[j] = @state[j], @state[i]
774
638
 
775
- def decrypt(data)
776
- unless data.size % BLOCKSIZE == 0
777
- raise EncryptionError,
778
- "Data must be 16-bytes padded (data size = #{data.size} bytes)"
639
+ output << (@state[@state[i] + @state[j] & 0xFF] ^ byte).chr
640
+ end
641
+ end
642
+
643
+ output
644
+ end
645
+
646
+ alias encrypt cipher
647
+ alias decrypt cipher
648
+
649
+ private
650
+
651
+ def init(key) #:nodoc:
652
+ state = (0..255).to_a
653
+
654
+ j = 0
655
+ 256.times do |i|
656
+ j = ( j + state[i] + key[i % key.size].ord ) & 0xFF
657
+ state[i], state[j] = state[j], state[i]
658
+ end
659
+
660
+ state
661
+ end
779
662
  end
780
663
 
781
- @iv = data.slice!(0, BLOCKSIZE)
664
+ #
665
+ # Pure Ruby implementation of the AES symmetric algorithm.
666
+ # Using mode CBC.
667
+ #
668
+ class AES
669
+ NROWS = 4
670
+ NCOLS = 4
671
+ BLOCKSIZE = NROWS * NCOLS
672
+
673
+ ROUNDS =
674
+ {
675
+ 16 => 10,
676
+ 24 => 12,
677
+ 32 => 14
678
+ }
679
+
680
+ #
681
+ # Rijndael S-box
682
+ #
683
+ SBOX =
684
+ [
685
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
686
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
687
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
688
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
689
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
690
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
691
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
692
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
693
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
694
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
695
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
696
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
697
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
698
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
699
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
700
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
701
+ ]
702
+
703
+ #
704
+ # Inverse of the Rijndael S-box
705
+ #
706
+ RSBOX =
707
+ [
708
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
709
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
710
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
711
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
712
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
713
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
714
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
715
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
716
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
717
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
718
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
719
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
720
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
721
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
722
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
723
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
724
+ ]
725
+
726
+ RCON =
727
+ [
728
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
729
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
730
+ 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
731
+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
732
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
733
+ 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
734
+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
735
+ 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
736
+ 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
737
+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
738
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
739
+ 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
740
+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
741
+ 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
742
+ 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
743
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb
744
+ ]
745
+
746
+ attr_writer :iv
747
+
748
+ def AES.encrypt(key, iv, data)
749
+ AES.new(key, iv).encrypt(data)
750
+ end
782
751
 
783
- if Origami::OPTIONS[:use_openssl]
784
- aes = OpenSSL::Cipher::Cipher.new("aes-#{@key.length << 3}-cbc").decrypt
785
- aes.iv = @iv
786
- aes.key = @key
787
- aes.padding = 0
752
+ def AES.decrypt(key, data)
753
+ AES.new(key, nil).decrypt(data)
754
+ end
755
+
756
+ def initialize(key, iv, use_padding = true)
757
+ unless key.size == 16 or key.size == 24 or key.size == 32
758
+ raise EncryptionError, "Key must have a length of 128, 192 or 256 bits."
759
+ end
788
760
 
789
- plain = (aes.update(data) + aes.final).unpack("C*")
790
- else
791
- plain = []
792
- plainblock = []
793
- prev_cipherblock = []
794
- nblocks = data.size / BLOCKSIZE
761
+ if not iv.nil? and iv.size != BLOCKSIZE
762
+ raise EncryptionError, "Initialization vector must have a length of #{BLOCKSIZE} bytes."
763
+ end
795
764
 
796
- first_round = true
797
- nblocks.times do |n|
798
- cipherblock = data[n * BLOCKSIZE, BLOCKSIZE].unpack("C*")
765
+ @key = key
766
+ @iv = iv
767
+ @use_padding = use_padding
768
+ end
799
769
 
800
- plainblock = aesDecrypt(cipherblock)
770
+ def encrypt(data)
771
+ if @iv.nil?
772
+ raise EncryptionError, "No initialization vector has been set."
773
+ end
801
774
 
802
- if first_round
803
- BLOCKSIZE.times do |i| plainblock[i] ^= @iv[i].ord end
804
- else
805
- BLOCKSIZE.times do |i| plainblock[i] ^= prev_cipherblock[i] end
775
+ if @use_padding
776
+ padlen = BLOCKSIZE - (data.size % BLOCKSIZE)
777
+ data << (padlen.chr * padlen)
778
+ end
779
+
780
+ if Origami::OPTIONS[:use_openssl]
781
+ aes = OpenSSL::Cipher::Cipher.new("aes-#{@key.length << 3}-cbc").encrypt
782
+ aes.iv = @iv
783
+ aes.key = @key
784
+ aes.padding = 0
785
+
786
+ @iv + aes.update(data) + aes.final
787
+ else
788
+ cipher = []
789
+ cipherblock = []
790
+ nblocks = data.size / BLOCKSIZE
791
+
792
+ first_round = true
793
+ nblocks.times do |n|
794
+ plainblock = data[n * BLOCKSIZE, BLOCKSIZE].unpack("C*")
795
+
796
+ if first_round
797
+ BLOCKSIZE.times do |i| plainblock[i] ^= @iv[i].ord end
798
+ else
799
+ BLOCKSIZE.times do |i| plainblock[i] ^= cipherblock[i] end
800
+ end
801
+
802
+ first_round = false
803
+ cipherblock = aes_encrypt(plainblock)
804
+ cipher.concat(cipherblock)
805
+ end
806
+
807
+ @iv + cipher.pack("C*")
808
+ end
806
809
  end
807
810
 
808
- first_round = false
809
- prev_cipherblock = cipherblock
810
- plain.concat(plainblock)
811
- end
812
- end
811
+ def decrypt(data)
812
+ unless data.size % BLOCKSIZE == 0
813
+ raise EncryptionError, "Data must be 16-bytes padded (data size = #{data.size} bytes)"
814
+ end
813
815
 
814
- if @use_padding
815
- padlen = plain[-1]
816
- unless (1..16) === padlen
817
- raise EncryptionError, "Incorrect padding length : #{padlen}"
818
- end
819
-
820
- padlen.times do
821
- pad = plain.pop
822
- raise EncryptionError,
823
- "Incorrect padding byte : 0x#{pad.to_s 16}" if pad != padlen
824
- end
825
- end
816
+ @iv = data.slice!(0, BLOCKSIZE)
826
817
 
827
- plain.pack("C*")
828
- end
818
+ if Origami::OPTIONS[:use_openssl]
819
+ aes = OpenSSL::Cipher::Cipher.new("aes-#{@key.length << 3}-cbc").decrypt
820
+ aes.iv = @iv
821
+ aes.key = @key
822
+ aes.padding = 0
829
823
 
830
- private
824
+ plain = (aes.update(data) + aes.final).unpack("C*")
825
+ else
826
+ plain = []
827
+ plainblock = []
828
+ prev_cipherblock = []
829
+ nblocks = data.size / BLOCKSIZE
830
+
831
+ first_round = true
832
+ nblocks.times do |n|
833
+ cipherblock = data[n * BLOCKSIZE, BLOCKSIZE].unpack("C*")
834
+
835
+ plainblock = aes_decrypt(cipherblock)
836
+
837
+ if first_round
838
+ BLOCKSIZE.times do |i| plainblock[i] ^= @iv[i].ord end
839
+ else
840
+ BLOCKSIZE.times do |i| plainblock[i] ^= prev_cipherblock[i] end
841
+ end
842
+
843
+ first_round = false
844
+ prev_cipherblock = cipherblock
845
+ plain.concat(plainblock)
846
+ end
847
+ end
831
848
 
832
- def rol(row, n = 1) #:nodoc
833
- n.times do row.push row.shift end ; row
834
- end
849
+ if @use_padding
850
+ padlen = plain[-1]
851
+ unless (1..16) === padlen
852
+ raise EncryptionError, "Incorrect padding length : #{padlen}"
853
+ end
835
854
 
836
- def ror(row, n = 1) #:nodoc:
837
- n.times do row.unshift row.pop end ; row
838
- end
855
+ padlen.times do
856
+ pad = plain.pop
857
+ raise EncryptionError, "Incorrect padding byte : 0x#{pad.to_s 16}" if pad != padlen
858
+ end
859
+ end
839
860
 
840
- def galoisMult(a, b) #:nodoc:
841
- p = 0
861
+ plain.pack("C*")
862
+ end
842
863
 
843
- 8.times do
844
- p ^= a if b[0] == 1
845
- highBit = a[7]
846
- a <<= 1
847
- a ^= 0x1b if highBit == 1
848
- b >>= 1
849
- end
864
+ private
850
865
 
851
- p % 256
852
- end
853
-
854
- def scheduleCore(word, iter) #:nodoc:
855
- rol(word)
856
- word.map! do |byte| SBOX[byte] end
857
- word[0] ^= RCON[iter]
858
-
859
- word
860
- end
861
-
862
- def transpose(m) #:nodoc:
863
- [
864
- m[NROWS * 0, NROWS],
865
- m[NROWS * 1, NROWS],
866
- m[NROWS * 2, NROWS],
867
- m[NROWS * 3, NROWS]
868
- ].transpose.flatten
869
- end
870
-
871
- #
872
- # AES round methods.
873
- #
874
-
875
- def createRoundKey(expandedKey, round = 0) #:nodoc:
876
- transpose(expandedKey[round * BLOCKSIZE, BLOCKSIZE])
877
- end
878
-
879
- def addRoundKey(roundKey) #:nodoc:
880
- BLOCKSIZE.times do |i| @state[i] ^= roundKey[i] end
881
- end
882
-
883
- def subBytes #:nodoc:
884
- BLOCKSIZE.times do |i| @state[i] = SBOX[ @state[i] ] end
885
- end
886
-
887
- def rsubBytes #:nodoc:
888
- BLOCKSIZE.times do |i| @state[i] = RSBOX[ @state[i] ] end
889
- end
890
-
891
- def shiftRows #:nodoc:
892
- NROWS.times do |i|
893
- @state[i * NCOLS, NCOLS] = rol(@state[i * NCOLS, NCOLS], i)
894
- end
895
- end
866
+ def rol(row, n = 1) #:nodoc
867
+ n.times do row.push row.shift end ; row
868
+ end
896
869
 
897
- def rshiftRows #:nodoc:
898
- NROWS.times do |i|
899
- @state[i * NCOLS, NCOLS] = ror(@state[i * NCOLS, NCOLS], i)
900
- end
901
- end
902
-
903
- def mixColumnWithField(column, field) #:nodoc:
904
- p = field
905
-
906
- column[0], column[1], column[2], column[3] =
907
- galoisMult(column[0], p[0]) ^ galoisMult(column[3], p[1]) ^ galoisMult(column[2], p[2]) ^ galoisMult(column[1], p[3]),
908
- galoisMult(column[1], p[0]) ^ galoisMult(column[0], p[1]) ^ galoisMult(column[3], p[2]) ^ galoisMult(column[2], p[3]),
909
- galoisMult(column[2], p[0]) ^ galoisMult(column[1], p[1]) ^ galoisMult(column[0], p[2]) ^ galoisMult(column[3], p[3]),
910
- galoisMult(column[3], p[0]) ^ galoisMult(column[2], p[1]) ^ galoisMult(column[1], p[2]) ^ galoisMult(column[0], p[3])
911
- end
912
-
913
- def mixColumn(column) #:nodoc:
914
- mixColumnWithField(column, [ 2, 1, 1, 3 ])
915
- end
916
-
917
- def rmixColumn(column) #:nodoc:
918
- mixColumnWithField(column, [ 14, 9, 13, 11 ])
919
- end
920
-
921
- def mixColumns #:nodoc:
922
- NCOLS.times do |c|
923
- column = []
924
- NROWS.times do |r| column << @state[c + r * NCOLS] end
925
- mixColumn(column)
926
- NROWS.times do |r| @state[c + r * NCOLS] = column[r] end
927
- end
928
- end
929
-
930
- def rmixColumns #:nodoc:
931
- NCOLS.times do |c|
932
- column = []
933
- NROWS.times do |r| column << @state[c + r * NCOLS] end
934
- rmixColumn(column)
935
- NROWS.times do |r| @state[c + r * NCOLS] = column[r] end
936
- end
937
- end
870
+ def ror(row, n = 1) #:nodoc:
871
+ n.times do row.unshift row.pop end ; row
872
+ end
938
873
 
939
- def expandKey(key) #:nodoc:
874
+ def galois_mult(a, b) #:nodoc:
875
+ p = 0
940
876
 
941
- key = key.unpack("C*")
942
- size = key.size
943
- expandedSize = 16 * (ROUNDS[key.size] + 1)
944
- rconIter = 1
945
- expandedKey = key[0, size]
877
+ 8.times do
878
+ p ^= a if b[0] == 1
879
+ highBit = a[7]
880
+ a <<= 1
881
+ a ^= 0x1b if highBit == 1
882
+ b >>= 1
883
+ end
946
884
 
947
- while expandedKey.size < expandedSize
948
- temp = expandedKey[-4, 4]
885
+ p % 256
886
+ end
949
887
 
950
- if expandedKey.size % size == 0
951
- scheduleCore(temp, rconIter)
952
- rconIter = rconIter.succ
953
- end
888
+ def schedule_core(word, iter) #:nodoc:
889
+ rol(word)
890
+ word.map! do |byte| SBOX[byte] end
891
+ word[0] ^= RCON[iter]
954
892
 
955
- temp.map! do |b| SBOX[b] end if size == 32 and expandedKey.size % size == 16
893
+ word
894
+ end
956
895
 
957
- temp.each do |b| expandedKey << (expandedKey[-size] ^ b) end
958
- end
896
+ def transpose(m) #:nodoc:
897
+ [
898
+ m[NROWS * 0, NROWS],
899
+ m[NROWS * 1, NROWS],
900
+ m[NROWS * 2, NROWS],
901
+ m[NROWS * 3, NROWS]
902
+ ].transpose.flatten
903
+ end
959
904
 
960
- expandedKey
961
- end
962
-
963
- def aesRound(roundKey) #:nodoc:
964
- subBytes
965
- #puts "after subBytes: #{@state.inspect}"
966
- shiftRows
967
- #puts "after shiftRows: #{@state.inspect}"
968
- mixColumns
969
- #puts "after mixColumns: #{@state.inspect}"
970
- addRoundKey(roundKey)
971
- #puts "roundKey = #{roundKey.inspect}"
972
- #puts "after addRoundKey: #{@state.inspect}"
973
- end
974
-
975
- def raesRound(roundKey) #:nodoc:
976
- addRoundKey(roundKey)
977
- rmixColumns
978
- rshiftRows
979
- rsubBytes
980
- end
981
-
982
- def aesEncrypt(block) #:nodoc:
983
- @state = transpose(block)
984
- expandedKey = expandKey(@key)
985
- rounds = ROUNDS[@key.size]
986
-
987
- aesMain(expandedKey, rounds)
988
- end
989
-
990
- def aesDecrypt(block) #:nodoc:
991
- @state = transpose(block)
992
- expandedKey = expandKey(@key)
993
- rounds = ROUNDS[@key.size]
994
-
995
- raesMain(expandedKey, rounds)
996
- end
997
-
998
- def aesMain(expandedKey, rounds) #:nodoc:
999
- #puts "expandedKey: #{expandedKey.inspect}"
1000
- roundKey = createRoundKey(expandedKey)
1001
- addRoundKey(roundKey)
1002
-
1003
- for i in 1..rounds-1
1004
- roundKey = createRoundKey(expandedKey, i)
1005
- aesRound(roundKey)
1006
- end
905
+ #
906
+ # AES round methods.
907
+ #
1007
908
 
1008
- roundKey = createRoundKey(expandedKey, rounds)
1009
- subBytes
1010
- shiftRows
1011
- addRoundKey(roundKey)
1012
-
1013
- transpose(@state)
1014
- end
1015
-
1016
- def raesMain(expandedKey, rounds) #:nodoc:
1017
-
1018
- roundKey = createRoundKey(expandedKey, rounds)
1019
- addRoundKey(roundKey)
1020
- rshiftRows
1021
- rsubBytes
1022
-
1023
- (rounds - 1).downto(1) do |i|
1024
- roundKey = createRoundKey(expandedKey, i)
1025
- raesRound(roundKey)
1026
- end
909
+ def create_round_key(expanded_key, round = 0) #:nodoc:
910
+ transpose(expanded_key[round * BLOCKSIZE, BLOCKSIZE])
911
+ end
1027
912
 
1028
- roundKey = createRoundKey(expandedKey)
1029
- addRoundKey(roundKey)
913
+ def add_round_key(roundKey) #:nodoc:
914
+ BLOCKSIZE.times do |i| @state[i] ^= roundKey[i] end
915
+ end
1030
916
 
1031
- transpose(@state)
1032
- end
917
+ def sub_bytes #:nodoc:
918
+ BLOCKSIZE.times do |i| @state[i] = SBOX[ @state[i] ] end
919
+ end
1033
920
 
1034
- end
1035
-
1036
- #
1037
- # Class representing a crypt filter Dictionary
1038
- #
1039
- class CryptFilterDictionary < Dictionary
1040
- include StandardObject
921
+ def r_sub_bytes #:nodoc:
922
+ BLOCKSIZE.times do |i| @state[i] = RSBOX[ @state[i] ] end
923
+ end
1041
924
 
1042
- field :Type, :Type => Name, :Default => :CryptFilter
1043
- field :CFM, :Type => Name, :Default => :None
1044
- field :AuthEvent, :Type => Name, :Default => :DocOpen
1045
- field :Length, :Type => Integer
1046
- end
925
+ def shift_rows #:nodoc:
926
+ NROWS.times do |i|
927
+ @state[i * NCOLS, NCOLS] = rol(@state[i * NCOLS, NCOLS], i)
928
+ end
929
+ end
1047
930
 
1048
- #
1049
- # Common class for encryption dictionaries.
1050
- #
1051
- class EncryptionDictionary < Dictionary
1052
- include StandardObject
1053
-
1054
- field :Filter, :Type => Name, :Default => :Standard, :Required => true
1055
- field :SubFilter, :Type => Name, :Version => "1.3"
1056
- field :V, :Type => Integer, :Default => 0
1057
- field :Length, :Type => Integer, :Default => 40, :Version => "1.4"
1058
- field :CF, :Type => Dictionary, :Version => "1.5"
1059
- field :StmF, :Type => Name, :Default => :Identity, :Version => "1.5"
1060
- field :StrF, :Type => Name, :Default => :Identity, :Version => "1.5"
1061
- field :EFF, :Type => Name, :Version => "1.6"
1062
- end
1063
-
1064
- #
1065
- # The standard security handler for PDF encryption.
1066
- #
1067
- module Standard
1068
-
1069
- PADDING = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A" #:nodoc:
1070
- PADDING.force_encoding('binary') if RUBY_VERSION >= '1.9'
1071
-
1072
- #
1073
- # Permission constants for encrypted documents.
1074
- #
1075
- module Permissions
1076
- RESERVED = 1 << 6 | 1 << 7 | 0xFFFFF000
1077
- PRINT = 1 << 2 | RESERVED
1078
- MODIFY_CONTENTS = 1 << 3 | RESERVED
1079
- COPY_CONTENTS = 1 << 4 | RESERVED
1080
- MODIFY_ANNOTATIONS = 1 << 5 | RESERVED
1081
- FILLIN_FORMS = 1 << 8 | RESERVED
1082
- EXTRACT_CONTENTS = 1 << 9 | RESERVED
1083
- ASSEMBLE_DOC = 1 << 10 | RESERVED
1084
- HIGH_QUALITY_PRINT = 1 << 11 | RESERVED
1085
-
1086
- ALL = PRINT | MODIFY_CONTENTS | COPY_CONTENTS | MODIFY_ANNOTATIONS | FILLIN_FORMS | EXTRACT_CONTENTS | ASSEMBLE_DOC | HIGH_QUALITY_PRINT
1087
- end
1088
-
1089
- #
1090
- # Class defining a standard encryption dictionary.
1091
- #
1092
- class Dictionary < EncryptionDictionary
1093
-
1094
- field :R, :Type => Number, :Required => true
1095
- field :O, :Type => String, :Required => true
1096
- field :U, :Type => String, :Required => true
1097
- field :OE, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1098
- field :UE, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1099
- field :Perms, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1100
- field :P, :Type => Integer, :Default => 0, :Required => true
1101
- field :EncryptMetadata, :Type => Boolean, :Default => true, :Version => "1.5"
1102
-
1103
- def pdf_version_required #:nodoc:
1104
- if self.R > 5
1105
- [ 1.7, 8 ]
1106
- else
1107
- super
1108
- end
1109
- end
1110
-
1111
- #
1112
- # Computes the key that will be used to encrypt/decrypt the document contents with user password.
1113
- #
1114
- def compute_user_encryption_key(userpassword, fileid)
1115
-
1116
- if self.R < 5
1117
- padded = pad_password(userpassword)
1118
- padded.force_encoding('binary') if RUBY_VERSION >= '1.9'
1119
-
1120
- padded << self.O
1121
- padded << [ self.P ].pack("i")
1122
-
1123
- padded << fileid
1124
-
1125
- encrypt_metadata = self.EncryptMetadata != false
1126
- padded << [ -1 ].pack("i") if self.R >= 4 and not encrypt_metadata
1127
-
1128
- key = Digest::MD5.digest(padded)
1129
-
1130
- 50.times { key = Digest::MD5.digest(key[0, self.Length / 8]) } if self.R >= 3
1131
-
1132
- if self.R == 2
1133
- key[0, 5]
1134
- elsif self.R >= 3
1135
- key[0, self.Length / 8]
931
+ def r_shift_rows #:nodoc:
932
+ NROWS.times do |i|
933
+ @state[i * NCOLS, NCOLS] = ror(@state[i * NCOLS, NCOLS], i)
934
+ end
1136
935
  end
1137
- else
1138
- passwd = password_to_utf8(userpassword)
1139
-
1140
- uks = self.U[40, 8]
1141
-
1142
- if self.R == 5
1143
- ukey = Digest::SHA256.digest(passwd + uks)
1144
- else
1145
- ukey = compute_hardened_hash(passwd, uks)
936
+
937
+ def mix_column_with_field(column, field) #:nodoc:
938
+ p = field
939
+
940
+ column[0], column[1], column[2], column[3] =
941
+ galois_mult(column[0], p[0]) ^
942
+ galois_mult(column[3], p[1]) ^
943
+ galois_mult(column[2], p[2]) ^
944
+ galois_mult(column[1], p[3]),
945
+
946
+ galois_mult(column[1], p[0]) ^
947
+ galois_mult(column[0], p[1]) ^
948
+ galois_mult(column[3], p[2]) ^
949
+ galois_mult(column[2], p[3]),
950
+
951
+ galois_mult(column[2], p[0]) ^
952
+ galois_mult(column[1], p[1]) ^
953
+ galois_mult(column[0], p[2]) ^
954
+ galois_mult(column[3], p[3]),
955
+
956
+ galois_mult(column[3], p[0]) ^
957
+ galois_mult(column[2], p[1]) ^
958
+ galois_mult(column[1], p[2]) ^
959
+ galois_mult(column[0], p[3])
1146
960
  end
1147
-
1148
- iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1149
- AES.new(ukey, nil, false).decrypt(iv + self.UE.value)
1150
- end
1151
- end
1152
961
 
1153
- #
1154
- # Computes the key that will be used to encrypt/decrypt the document contents with owner password.
1155
- # Revision 5 and above.
1156
- #
1157
- def compute_owner_encryption_key(ownerpassword)
1158
- if self.R >= 5
1159
- passwd = password_to_utf8(ownerpassword)
962
+ def mix_column(column) #:nodoc:
963
+ mix_column_with_field(column, [ 2, 1, 1, 3 ])
964
+ end
1160
965
 
1161
- oks = self.O[40, 8]
966
+ def r_mix_column_(column) #:nodoc:
967
+ mix_column_with_field(column, [ 14, 9, 13, 11 ])
968
+ end
1162
969
 
1163
- if self.R == 5
1164
- okey = Digest::SHA256.digest(passwd + oks + self.U)
1165
- else
1166
- okey = compute_hardened_hash(passwd, oks, self.U)
970
+ def mix_columns #:nodoc:
971
+ NCOLS.times do |c|
972
+ column = []
973
+ NROWS.times do |r| column << @state[c + r * NCOLS] end
974
+ mix_column(column)
975
+ NROWS.times do |r| @state[c + r * NCOLS] = column[r] end
976
+ end
1167
977
  end
1168
978
 
1169
- iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1170
- AES.new(okey, nil, false).decrypt(iv + self.OE.value)
1171
- end
1172
- end
979
+ def r_mix_columns #:nodoc:
980
+ NCOLS.times do |c|
981
+ column = []
982
+ NROWS.times do |r| column << @state[c + r * NCOLS] end
983
+ r_mix_column_(column)
984
+ NROWS.times do |r| @state[c + r * NCOLS] = column[r] end
985
+ end
986
+ end
1173
987
 
1174
- #
1175
- # Set up document passwords.
1176
- #
1177
- def set_passwords(ownerpassword, userpassword, salt = nil)
1178
- if self.R < 5
1179
- key = compute_owner_key(ownerpassword)
1180
- upadded = pad_password(userpassword)
1181
-
1182
- owner_key = ARC4.encrypt(key, upadded)
1183
- 19.times { |i| owner_key = ARC4.encrypt(xor(key,i+1), owner_key) } if self.R >= 3
1184
-
1185
- self.O = owner_key
1186
- self.U = compute_user_password(userpassword, salt)
1187
-
1188
- else
1189
- upass = password_to_utf8(userpassword)
1190
- opass = password_to_utf8(ownerpassword)
1191
-
1192
- uvs, uks, ovs, oks = ::Array.new(4) { Encryption.rand_bytes(8) }
1193
- file_key = Encryption.strong_rand_bytes(32)
1194
- iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1195
-
1196
- if self.R == 5
1197
- self.U = Digest::SHA256.digest(upass + uvs) + uvs + uks
1198
- self.O = Digest::SHA256.digest(opass + ovs + self.U) + ovs + oks
1199
- ukey = Digest::SHA256.digest(upass + uks)
1200
- okey = Digest::SHA256.digest(opass + oks + self.U)
1201
- else
1202
- self.U = compute_hardened_hash(upass, uvs) + uvs + uks
1203
- self.O = compute_hardened_hash(opass, ovs, self.U) + ovs + oks
1204
- ukey = compute_hardened_hash(upass, uks)
1205
- okey = compute_hardened_hash(opass, oks, self.U)
988
+ def expand_key(key) #:nodoc:
989
+ key = key.unpack("C*")
990
+ size = key.size
991
+ expanded_size = 16 * (ROUNDS[key.size] + 1)
992
+ rcon_iter = 1
993
+ expanded_key = key[0, size]
994
+
995
+ while expanded_key.size < expanded_size
996
+ temp = expanded_key[-4, 4]
997
+
998
+ if expanded_key.size % size == 0
999
+ schedule_core(temp, rcon_iter)
1000
+ rcon_iter = rcon_iter.succ
1001
+ end
1002
+
1003
+ temp.map! do |b| SBOX[b] end if size == 32 and expanded_key.size % size == 16
1004
+
1005
+ temp.each do |b| expanded_key << (expanded_key[-size] ^ b) end
1006
+ end
1007
+
1008
+ expanded_key
1206
1009
  end
1207
1010
 
1208
- self.UE = AES.new(ukey, iv, false).encrypt(file_key)[iv.size, 32]
1209
- self.OE = AES.new(okey, iv, false).encrypt(file_key)[iv.size, 32]
1011
+ def aes_round(round_key) #:nodoc:
1012
+ sub_bytes
1013
+ #puts "after sub_bytes: #{@state.inspect}"
1014
+ shift_rows
1015
+ #puts "after shift_rows: #{@state.inspect}"
1016
+ mix_columns
1017
+ #puts "after mix_columns: #{@state.inspect}"
1018
+ add_round_key(round_key)
1019
+ #puts "roundKey = #{roundKey.inspect}"
1020
+ #puts "after add_round_key: #{@state.inspect}"
1021
+ end
1210
1022
 
1211
- perms =
1212
- [ self.P ].pack("V") + # 0-3
1213
- [ -1 ].pack("V") + # 4-7
1214
- (self.EncryptMetadata == true ? "T" : "F") + # 8
1215
- "adb" + # 9-11
1216
- [ 0 ].pack("V") # 12-15
1023
+ def r_aes_round(round_key) #:nodoc:
1024
+ add_round_key(round_key)
1025
+ r_mix_columns
1026
+ r_shift_rows
1027
+ r_sub_bytes
1028
+ end
1217
1029
 
1218
- self.Perms = AES.new(file_key, iv, false).encrypt(perms)[iv.size, 16]
1030
+ def aes_encrypt(block) #:nodoc:
1031
+ @state = transpose(block)
1032
+ expanded_key = expand_key(@key)
1033
+ rounds = ROUNDS[@key.size]
1219
1034
 
1220
- file_key
1221
- end
1222
- end
1223
-
1224
- #
1225
- # Checks user password.
1226
- # For version 2,3 and 4, _salt_ is the document ID.
1227
- # For version 5 and 6, _salt_ is the User Key Salt.
1228
- #
1229
- def is_user_password?(pass, salt)
1230
- if self.R == 2
1231
- compute_user_password(pass, salt) == self.U
1232
- elsif self.R == 3 or self.R == 4
1233
- compute_user_password(pass, salt)[0, 16] == self.U[0, 16]
1234
- elsif self.R == 5
1235
- uvs = self.U[32, 8]
1236
- Digest::SHA256.digest(password_to_utf8(pass) + uvs) == self.U[0, 32]
1237
- elsif self.R == 6
1238
- uvs = self.U[32, 8]
1239
- compute_hardened_hash(password_to_utf8(pass), uvs) == self.U[0, 32]
1240
- end
1241
- end
1242
-
1243
- #
1244
- # Checks owner password.
1245
- # For version 2,3 and 4, _salt_ is the document ID.
1246
- # For version 5, _salt_ is (Owner Key Salt + U)
1247
- #
1248
- def is_owner_password?(pass, salt)
1249
-
1250
- if self.R < 5
1251
- user_password = retrieve_user_password(pass)
1252
- is_user_password?(user_password, salt)
1253
- elsif self.R == 5
1254
- ovs = self.O[32, 8]
1255
- Digest::SHA256.digest(password_to_utf8(pass) + ovs + self.U) == self.O[0, 32]
1256
- elsif self.R == 6
1257
- ovs = self.O[32, 8]
1258
- compute_hardened_hash(password_to_utf8(pass), ovs, self.U[0,48]) == self.O[0, 32]
1259
- end
1260
- end
1035
+ aes_main(expanded_key, rounds)
1036
+ end
1261
1037
 
1262
- #
1263
- # Retrieve user password from owner password.
1264
- # Cannot be used with revision 5.
1265
- #
1266
- def retrieve_user_password(ownerpassword)
1267
- key = compute_owner_key(ownerpassword)
1268
-
1269
- if self.R == 2
1270
- ARC4.decrypt(key, self.O)
1271
- elsif self.R == 3 or self.R == 4
1272
- user_password = ARC4.decrypt(xor(key, 19), self.O)
1273
- 19.times { |i| user_password = ARC4.decrypt(xor(key, 18-i), user_password) }
1274
-
1275
- user_password
1276
- end
1038
+ def aes_decrypt(block) #:nodoc:
1039
+ @state = transpose(block)
1040
+ expanded_key = expand_key(@key)
1041
+ rounds = ROUNDS[@key.size]
1042
+
1043
+ r_aes_main(expanded_key, rounds)
1044
+ end
1045
+
1046
+ def aes_main(expanded_key, rounds) #:nodoc:
1047
+ #puts "expandedKey: #{expandedKey.inspect}"
1048
+ round_key = create_round_key(expanded_key)
1049
+ add_round_key(round_key)
1050
+
1051
+ for i in 1..rounds-1
1052
+ round_key = create_round_key(expanded_key, i)
1053
+ aes_round(round_key)
1054
+ end
1055
+
1056
+ round_key = create_round_key(expanded_key, rounds)
1057
+ sub_bytes
1058
+ shift_rows
1059
+ add_round_key(round_key)
1060
+
1061
+ transpose(@state)
1062
+ end
1063
+
1064
+ def r_aes_main(expanded_key, rounds) #:nodoc:
1065
+ round_key = create_round_key(expanded_key, rounds)
1066
+ add_round_key(round_key)
1067
+ r_shift_rows
1068
+ r_sub_bytes
1069
+
1070
+ (rounds - 1).downto(1) do |i|
1071
+ round_key = create_round_key(expanded_key, i)
1072
+ r_aes_round(round_key)
1073
+ end
1074
+
1075
+ round_key = create_round_key(expanded_key)
1076
+ add_round_key(round_key)
1077
+
1078
+ transpose(@state)
1079
+ end
1277
1080
  end
1278
-
1279
- private
1280
1081
 
1281
1082
  #
1282
- # Used to encrypt/decrypt the O field.
1283
- # Rev 2,3,4: O = crypt(user_pass, owner_key).
1284
- # Rev 5: unused.
1083
+ # Class representing a crypt filter Dictionary
1285
1084
  #
1286
- def compute_owner_key(ownerpassword) #:nodoc:
1287
-
1288
- opadded = pad_password(ownerpassword)
1289
-
1290
- hash = Digest::MD5.digest(opadded)
1291
- 50.times { hash = Digest::MD5.digest(hash) } if self.R >= 3
1292
-
1293
- if self.R == 2
1294
- hash[0, 5]
1295
- elsif self.R >= 3
1296
- hash[0, self.Length / 8]
1297
- end
1085
+ class CryptFilterDictionary < Dictionary
1086
+ include StandardObject
1087
+
1088
+ field :Type, :Type => Name, :Default => :CryptFilter
1089
+ field :CFM, :Type => Name, :Default => :None
1090
+ field :AuthEvent, :Type => Name, :Default => :DocOpen
1091
+ field :Length, :Type => Integer
1298
1092
  end
1299
-
1093
+
1300
1094
  #
1301
- # Compute the value of the U field.
1302
- # Cannot be used with revision 5.
1095
+ # Common class for encryption dictionaries.
1303
1096
  #
1304
- def compute_user_password(userpassword, salt) #:nodoc:
1305
-
1306
- if self.R == 2
1307
- key = compute_user_encryption_key(userpassword, salt)
1308
- user_key = ARC4.encrypt(key, PADDING)
1309
- elsif self.R == 3 or self.R == 4
1310
- key = compute_user_encryption_key(userpassword, salt)
1311
-
1312
- upadded = PADDING + salt
1313
- hash = Digest::MD5.digest(upadded)
1314
-
1315
- user_key = ARC4.encrypt(key, hash)
1316
-
1317
- 19.times { |i| user_key = ARC4.encrypt(xor(key,i+1), user_key) }
1318
-
1319
- user_key.ljust(32, 0xFF.chr)
1320
- end
1097
+ class EncryptionDictionary < Dictionary
1098
+ include StandardObject
1099
+
1100
+ field :Filter, :Type => Name, :Default => :Standard, :Required => true
1101
+ field :SubFilter, :Type => Name, :Version => "1.3"
1102
+ field :V, :Type => Integer, :Default => 0
1103
+ field :Length, :Type => Integer, :Default => 40, :Version => "1.4"
1104
+ field :CF, :Type => Dictionary, :Version => "1.5"
1105
+ field :StmF, :Type => Name, :Default => :Identity, :Version => "1.5"
1106
+ field :StrF, :Type => Name, :Default => :Identity, :Version => "1.5"
1107
+ field :EFF, :Type => Name, :Version => "1.6"
1321
1108
  end
1322
1109
 
1323
1110
  #
1324
- # Computes hardened hash used in revision 6 (extension level 8).
1111
+ # The standard security handler for PDF encryption.
1325
1112
  #
1326
- def compute_hardened_hash(password, salt, vector = '')
1327
- block_size = 32
1328
- input = Digest::SHA256.digest(password + salt + vector) + "\x00" * 32
1329
- key = input[0, 16]
1330
- iv = input[16, 16]
1331
- digest, aes, h, x = nil, nil, nil, nil
1332
-
1333
- i = 0
1334
- while i < 64 or i < x[-1].ord + 32
1335
- j = 0
1336
- block = input[0, block_size]
1337
-
1338
- if Origami::OPTIONS[:use_openssl]
1339
- aes = OpenSSL::Cipher::Cipher.new("aes-128-cbc").encrypt
1340
- aes.iv = iv
1341
- aes.key = key
1342
- aes.padding = 0
1343
- else
1344
- fail "You need OpenSSL support to encrypt/decrypt documents with this method"
1113
+ module Standard
1114
+ PADDING = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A".b #:nodoc:
1115
+
1116
+ #
1117
+ # Permission constants for encrypted documents.
1118
+ #
1119
+ module Permissions
1120
+ RESERVED = 1 << 6 | 1 << 7 | 0xFFFFF000
1121
+ PRINT = 1 << 2 | RESERVED
1122
+ MODIFY_CONTENTS = 1 << 3 | RESERVED
1123
+ COPY_CONTENTS = 1 << 4 | RESERVED
1124
+ MODIFY_ANNOTATIONS = 1 << 5 | RESERVED
1125
+ FILLIN_FORMS = 1 << 8 | RESERVED
1126
+ EXTRACT_CONTENTS = 1 << 9 | RESERVED
1127
+ ASSEMBLE_DOC = 1 << 10 | RESERVED
1128
+ HIGH_QUALITY_PRINT = 1 << 11 | RESERVED
1129
+
1130
+ ALL = PRINT | MODIFY_CONTENTS | COPY_CONTENTS |
1131
+ MODIFY_ANNOTATIONS | FILLIN_FORMS | EXTRACT_CONTENTS |
1132
+ ASSEMBLE_DOC | HIGH_QUALITY_PRINT
1345
1133
  end
1346
1134
 
1347
- 64.times do |j|
1348
- x = ''
1349
- x += aes.update(password) unless password.empty?
1350
- x += aes.update(block)
1351
- x += aes.update(vector) unless vector.empty?
1135
+ #
1136
+ # Class defining a standard encryption dictionary.
1137
+ #
1138
+ class Dictionary < EncryptionDictionary
1139
+
1140
+ field :R, :Type => Number, :Required => true
1141
+ field :O, :Type => String, :Required => true
1142
+ field :U, :Type => String, :Required => true
1143
+ field :OE, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1144
+ field :UE, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1145
+ field :Perms, :Type => String, :Version => '1.7', :ExtensionLevel => 3
1146
+ field :P, :Type => Integer, :Default => 0, :Required => true
1147
+ field :EncryptMetadata, :Type => Boolean, :Default => true, :Version => "1.5"
1148
+
1149
+ def version_required #:nodoc:
1150
+ if self.R > 5
1151
+ [ 1.7, 8 ]
1152
+ else
1153
+ super
1154
+ end
1155
+ end
1352
1156
 
1353
- if j == 0
1354
- block_size = 32 + (x.unpack("C16").inject(0) {|a,b| a+b} % 3) * 16
1355
- digest = Digest::SHA2.new(block_size << 3)
1356
- end
1157
+ #
1158
+ # Computes the key that will be used to encrypt/decrypt the document contents with user password.
1159
+ #
1160
+ def compute_user_encryption_key(userpassword, fileid)
1161
+ if self.R < 5
1162
+ padded = pad_password(userpassword)
1163
+ padded.force_encoding('binary')
1357
1164
 
1358
- digest.update(x)
1359
- end
1165
+ padded << self.O
1166
+ padded << [ self.P ].pack("i")
1360
1167
 
1361
- h = digest.digest
1362
- key = h[0, 16]
1363
- input[0, block_size] = h[0, block_size]
1364
- iv = h[16, 16]
1168
+ padded << fileid
1365
1169
 
1366
- i = i + 1
1367
- end
1170
+ encrypt_metadata = self.EncryptMetadata != false
1171
+ padded << [ -1 ].pack("i") if self.R >= 4 and not encrypt_metadata
1368
1172
 
1369
- h[0, 32]
1370
- end
1371
-
1372
- def xor(str, byte) #:nodoc:
1373
- str.split(//).map!{|c| (c[0].ord ^ byte).chr }.join
1374
- end
1375
-
1376
- def pad_password(password) #:nodoc:
1377
- return PADDING.dup if password.empty? # Fix for Ruby 1.9 bug
1378
- password[0,32].ljust(32, PADDING)
1379
- end
1173
+ key = Digest::MD5.digest(padded)
1174
+
1175
+ 50.times { key = Digest::MD5.digest(key[0, self.Length / 8]) } if self.R >= 3
1176
+
1177
+ if self.R == 2
1178
+ key[0, 5]
1179
+ elsif self.R >= 3
1180
+ key[0, self.Length / 8]
1181
+ end
1182
+ else
1183
+ passwd = password_to_utf8(userpassword)
1380
1184
 
1381
- def password_to_utf8(passwd) #:nodoc:
1382
- Origami::ByteString.new(passwd).to_utf8[0, 127]
1185
+ uks = self.U[40, 8]
1186
+
1187
+ if self.R == 5
1188
+ ukey = Digest::SHA256.digest(passwd + uks)
1189
+ else
1190
+ ukey = compute_hardened_hash(passwd, uks)
1191
+ end
1192
+
1193
+ iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1194
+ AES.new(ukey, nil, false).decrypt(iv + self.UE.value)
1195
+ end
1196
+ end
1197
+
1198
+ #
1199
+ # Computes the key that will be used to encrypt/decrypt the document contents with owner password.
1200
+ # Revision 5 and above.
1201
+ #
1202
+ def compute_owner_encryption_key(ownerpassword)
1203
+ if self.R >= 5
1204
+ passwd = password_to_utf8(ownerpassword)
1205
+
1206
+ oks = self.O[40, 8]
1207
+
1208
+ if self.R == 5
1209
+ okey = Digest::SHA256.digest(passwd + oks + self.U)
1210
+ else
1211
+ okey = compute_hardened_hash(passwd, oks, self.U)
1212
+ end
1213
+
1214
+ iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1215
+ AES.new(okey, nil, false).decrypt(iv + self.OE.value)
1216
+ end
1217
+ end
1218
+
1219
+ #
1220
+ # Set up document passwords.
1221
+ #
1222
+ def set_passwords(ownerpassword, userpassword, salt = nil)
1223
+ if self.R < 5
1224
+ key = compute_owner_key(ownerpassword)
1225
+ upadded = pad_password(userpassword)
1226
+
1227
+ owner_key = RC4.encrypt(key, upadded)
1228
+ 19.times { |i| owner_key = RC4.encrypt(xor(key,i+1), owner_key) } if self.R >= 3
1229
+
1230
+ self.O = owner_key
1231
+ self.U = compute_user_password(userpassword, salt)
1232
+
1233
+ else
1234
+ upass = password_to_utf8(userpassword)
1235
+ opass = password_to_utf8(ownerpassword)
1236
+
1237
+ uvs, uks, ovs, oks = ::Array.new(4) { Encryption.rand_bytes(8) }
1238
+ file_key = Encryption.strong_rand_bytes(32)
1239
+ iv = ::Array.new(AES::BLOCKSIZE, 0).pack("C*")
1240
+
1241
+ if self.R == 5
1242
+ self.U = Digest::SHA256.digest(upass + uvs) + uvs + uks
1243
+ self.O = Digest::SHA256.digest(opass + ovs + self.U) + ovs + oks
1244
+ ukey = Digest::SHA256.digest(upass + uks)
1245
+ okey = Digest::SHA256.digest(opass + oks + self.U)
1246
+ else
1247
+ self.U = compute_hardened_hash(upass, uvs) + uvs + uks
1248
+ self.O = compute_hardened_hash(opass, ovs, self.U) + ovs + oks
1249
+ ukey = compute_hardened_hash(upass, uks)
1250
+ okey = compute_hardened_hash(opass, oks, self.U)
1251
+ end
1252
+
1253
+ self.UE = AES.new(ukey, iv, false).encrypt(file_key)[iv.size, 32]
1254
+ self.OE = AES.new(okey, iv, false).encrypt(file_key)[iv.size, 32]
1255
+
1256
+ perms =
1257
+ [ self.P ].pack("V") + # 0-3
1258
+ [ -1 ].pack("V") + # 4-7
1259
+ (self.EncryptMetadata == true ? "T" : "F") + # 8
1260
+ "adb" + # 9-11
1261
+ [ 0 ].pack("V") # 12-15
1262
+
1263
+ self.Perms = AES.new(file_key, iv, false).encrypt(perms)[iv.size, 16]
1264
+
1265
+ file_key
1266
+ end
1267
+ end
1268
+
1269
+ #
1270
+ # Checks user password.
1271
+ # For version 2,3 and 4, _salt_ is the document ID.
1272
+ # For version 5 and 6, _salt_ is the User Key Salt.
1273
+ #
1274
+ def is_user_password?(pass, salt)
1275
+
1276
+ if self.R == 2
1277
+ compute_user_password(pass, salt) == self.U
1278
+ elsif self.R == 3 or self.R == 4
1279
+ compute_user_password(pass, salt)[0, 16] == self.U[0, 16]
1280
+ elsif self.R == 5
1281
+ uvs = self.U[32, 8]
1282
+ Digest::SHA256.digest(password_to_utf8(pass) + uvs) == self.U[0, 32]
1283
+ elsif self.R == 6
1284
+ uvs = self.U[32, 8]
1285
+ compute_hardened_hash(password_to_utf8(pass), uvs) == self.U[0, 32]
1286
+ end
1287
+ end
1288
+
1289
+ #
1290
+ # Checks owner password.
1291
+ # For version 2,3 and 4, _salt_ is the document ID.
1292
+ # For version 5, _salt_ is (Owner Key Salt + U)
1293
+ #
1294
+ def is_owner_password?(pass, salt)
1295
+
1296
+ if self.R < 5
1297
+ user_password = retrieve_user_password(pass)
1298
+ is_user_password?(user_password, salt)
1299
+ elsif self.R == 5
1300
+ ovs = self.O[32, 8]
1301
+ Digest::SHA256.digest(password_to_utf8(pass) + ovs + self.U) == self.O[0, 32]
1302
+ elsif self.R == 6
1303
+ ovs = self.O[32, 8]
1304
+ compute_hardened_hash(password_to_utf8(pass), ovs, self.U[0,48]) == self.O[0, 32]
1305
+ end
1306
+ end
1307
+
1308
+ #
1309
+ # Retrieve user password from owner password.
1310
+ # Cannot be used with revision 5.
1311
+ #
1312
+ def retrieve_user_password(ownerpassword)
1313
+
1314
+ key = compute_owner_key(ownerpassword)
1315
+
1316
+ if self.R == 2
1317
+ RC4.decrypt(key, self.O)
1318
+ elsif self.R == 3 or self.R == 4
1319
+ user_password = RC4.decrypt(xor(key, 19), self.O)
1320
+ 19.times { |i| user_password = RC4.decrypt(xor(key, 18-i), user_password) }
1321
+
1322
+ user_password
1323
+ end
1324
+ end
1325
+
1326
+ private
1327
+
1328
+ #
1329
+ # Used to encrypt/decrypt the O field.
1330
+ # Rev 2,3,4: O = crypt(user_pass, owner_key).
1331
+ # Rev 5: unused.
1332
+ #
1333
+ def compute_owner_key(ownerpassword) #:nodoc:
1334
+
1335
+ opadded = pad_password(ownerpassword)
1336
+
1337
+ hash = Digest::MD5.digest(opadded)
1338
+ 50.times { hash = Digest::MD5.digest(hash) } if self.R >= 3
1339
+
1340
+ if self.R == 2
1341
+ hash[0, 5]
1342
+ elsif self.R >= 3
1343
+ hash[0, self.Length / 8]
1344
+ end
1345
+ end
1346
+
1347
+ #
1348
+ # Compute the value of the U field.
1349
+ # Cannot be used with revision 5.
1350
+ #
1351
+ def compute_user_password(userpassword, salt) #:nodoc:
1352
+
1353
+ if self.R == 2
1354
+ key = compute_user_encryption_key(userpassword, salt)
1355
+ user_key = RC4.encrypt(key, PADDING)
1356
+ elsif self.R == 3 or self.R == 4
1357
+ key = compute_user_encryption_key(userpassword, salt)
1358
+
1359
+ upadded = PADDING + salt
1360
+ hash = Digest::MD5.digest(upadded)
1361
+
1362
+ user_key = RC4.encrypt(key, hash)
1363
+
1364
+ 19.times { |i| user_key = RC4.encrypt(xor(key,i+1), user_key) }
1365
+
1366
+ user_key.ljust(32, 0xFF.chr)
1367
+ end
1368
+ end
1369
+
1370
+ #
1371
+ # Computes hardened hash used in revision 6 (extension level 8).
1372
+ #
1373
+ def compute_hardened_hash(password, salt, vector = '')
1374
+ block_size = 32
1375
+ input = Digest::SHA256.digest(password + salt + vector) + "\x00" * 32
1376
+ key = input[0, 16]
1377
+ iv = input[16, 16]
1378
+ digest, aes, h, x = nil, nil, nil, nil
1379
+
1380
+ i = 0
1381
+ while i < 64 or i < x[-1].ord + 32
1382
+
1383
+ block = input[0, block_size]
1384
+
1385
+ if Origami::OPTIONS[:use_openssl]
1386
+ aes = OpenSSL::Cipher::Cipher.new("aes-128-cbc").encrypt
1387
+ aes.iv = iv
1388
+ aes.key = key
1389
+ aes.padding = 0
1390
+ else
1391
+ fail "You need OpenSSL support to encrypt/decrypt documents with this method"
1392
+ end
1393
+
1394
+ 64.times do |j|
1395
+ x = ''
1396
+ x += aes.update(password) unless password.empty?
1397
+ x += aes.update(block)
1398
+ x += aes.update(vector) unless vector.empty?
1399
+
1400
+ if j == 0
1401
+ block_size = 32 + (x.unpack("C16").inject(0) {|a,b| a+b} % 3) * 16
1402
+ digest = Digest::SHA2.new(block_size << 3)
1403
+ end
1404
+
1405
+ digest.update(x)
1406
+ end
1407
+
1408
+ h = digest.digest
1409
+ key = h[0, 16]
1410
+ input[0, block_size] = h[0, block_size]
1411
+ iv = h[16, 16]
1412
+
1413
+ i = i + 1
1414
+ end
1415
+
1416
+ h[0, 32]
1417
+ end
1418
+
1419
+ def xor(str, byte) #:nodoc:
1420
+ str.split(//).map!{|c| (c[0].ord ^ byte).chr }.join
1421
+ end
1422
+
1423
+ def pad_password(password) #:nodoc:
1424
+ return PADDING.dup if password.empty? # Fix for Ruby 1.9 bug
1425
+ password[0,32].ljust(32, PADDING)
1426
+ end
1427
+
1428
+ def password_to_utf8(passwd) #:nodoc:
1429
+ LiteralString.new(passwd).to_utf8[0, 127]
1430
+ end
1431
+ end
1383
1432
  end
1384
-
1385
- end
1386
-
1387
1433
  end
1388
-
1389
- end
1390
1434
 
1391
1435
  end
1392
-
1393
- __END__
1394
- def hexprint(str)
1395
- hex = ""
1396
- str.each_byte do |b|
1397
- digit = b.to_s(16)
1398
- digit = "0" + digit if digit.size == 1
1399
- hex << digit
1400
- end
1401
-
1402
- puts hex.upcase
1403
- end
1404
-