Class: Rpdf2txt::PdfEncrypt
Defined Under Namespace
Classes: DecryptionError
Constant Summary
collapse
- 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"
Instance Attribute Summary
Attributes inherited from PdfObject
#attributes, #decoder, #oid, #src
Instance Method Summary
collapse
Methods inherited from PdfObject
#_parse_attributes, #build_tree, #catalogue_object, #decoded_stream, #extract_attribute_stream, #initialize, #parse_attributes, #revision_id
Instance Method Details
#arc4(key, input) ⇒ Object
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# File 'lib/rpdf2txt/object.rb', line 132
def arc4(key, input)
output = ''
s, j, k = (0..255).to_a, 0, (key*256)[0,256].unpack('C*')
(0..255).each { |x|
j = (j + s[x] + k[x]) % 256
s[x], s[j] = s[j], s[x]
}
i = j = 0
input.each_byte { |b|
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
output << (b ^ s[(s[i] + s[j])%256]).chr
}
output
end
|
#big_endian? ⇒ Boolean
182
183
184
185
186
187
188
189
|
# File 'lib/rpdf2txt/object.rb', line 182
def big_endian?
if ([1].pack('I*') == "\000\000\000\001")
true
else
false
end
end
|
#compute_user_key(encryption_key) ⇒ Object
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/rpdf2txt/object.rb', line 148
def compute_user_key encryption_key
if revision < 3
pdf_escape arc4(encryption_key, PADDING)
else
crypt = Digest::MD5.digest PADDING + file_id
20.times do |xor|
key = encryption_key.unpack('C*').collect! do |byte|
byte ^ xor
end.pack('C*')
crypt = arc4(key, crypt)
end
pdf_escape crypt
end
end
|
#decrypt(pdf_object) ⇒ Object
162
163
164
165
166
|
# File 'lib/rpdf2txt/object.rb', line 162
def decrypt(pdf_object)
arc4_key = decrypt_key(pdf_object)
stream = pdf_object.raw_stream
arc4(arc4_key, stream)
end
|
#decrypt_key(pdf_object) ⇒ Object
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
# File 'lib/rpdf2txt/object.rb', line 167
def decrypt_key(pdf_object)
oid = pdf_object.oid
rev_id = pdf_object.revision_id
if(self.big_endian?)
oid_three_bytes = [oid].pack('I*').reverse[0,3]
rev_id_two_bytes = [rev_id].pack('I*').reverse[0,2]
else
oid_three_bytes = [oid].pack('I*')[0,3]
rev_id_two_bytes = [rev_id].pack('I*')[0,2]
end
input = encryption_key << oid_three_bytes << rev_id_two_bytes
digest = Digest::MD5.digest(input)
digest[0,[keylength + 5,16].min]
end
|
#encryption_key ⇒ Object
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# File 'lib/rpdf2txt/object.rb', line 190
def encryption_key
input_string = PADDING.dup
input_string << owner_key
input_string << permission_flag
input_string << file_id
digest = Digest::MD5.digest(input_string)
uk = user_key
if revision >= 3
50.times do digest = Digest::MD5.digest(digest[0,keylength]) end
uk = uk[0,16]
end
encryption_key = digest[0,keylength]
test_key = compute_user_key encryption_key
encryption_key
end
|
218
219
220
|
# File 'lib/rpdf2txt/object.rb', line 218
def file_id
[@file_id].pack("H*")
end
|
#file_id=(file_id) ⇒ Object
215
216
217
|
# File 'lib/rpdf2txt/object.rb', line 215
def file_id= (file_id)
@file_id = file_id
end
|
#keylength ⇒ Object
221
222
223
|
# File 'lib/rpdf2txt/object.rb', line 221
def keylength
@keylength ||= (@attributes[:length] || 40).to_i / 8
end
|
#owner_key ⇒ Object
224
225
226
|
# File 'lib/rpdf2txt/object.rb', line 224
def owner_key
@attributes[:o].to_s
end
|
#permission_flag ⇒ Object
227
228
229
230
231
232
233
|
# File 'lib/rpdf2txt/object.rb', line 227
def permission_flag
if (self.big_endian?)
[@attributes[:p].to_i].pack('I*').reverse
else
[@attributes[:p].to_i].pack('I*')
end
end
|
234
235
236
|
# File 'lib/rpdf2txt/object.rb', line 234
def revision
@attributes[:r].to_i
end
|
237
238
239
|
# File 'lib/rpdf2txt/object.rb', line 237
def user_key
@attributes[:u].to_s
end
|