lib/hexapdf/encryption/security_handler.rb in hexapdf-0.5.0 vs lib/hexapdf/encryption/security_handler.rb in hexapdf-0.6.0

- old
+ new

@@ -130,10 +130,36 @@ # encryption_dictionary_class:: # Returns the class that is used for the encryption dictionary. Should be derived from the # EncryptionDictionary class. class SecurityHandler + # Provides additional encryption specific information for HexaPDF::StreamData objects. + class EncryptedStreamData < StreamData + + # The encryption key. + attr_reader :key + + # The encryption algorithm. + attr_reader :algorithm + + # Creates a new encrypted stream data object by utilizing the given stream data object as + # template. The arguments +key+ and +algorithm+ are used for decrypting purposes. + def initialize(obj, key, algorithm) + obj.instance_variables.each {|v| instance_variable_set(v, obj.instance_variable_get(v))} + @key = key + @algorithm = algorithm + end + + alias :undecrypted_fiber :fiber + + # Returns a fiber like HexaPDF::StreamData#fiber, but one wrapped in a decrypting fiber. + def fiber(*args) + @algorithm.decryption_fiber(@key, super(*args)) + end + + end + # :call-seq: # SecurityHandler.set_up_encryption(document, handler_name, **options) -> handler # # Sets up and returns the security handler with the specified name for the document and # modifies then document's encryption dictionary accordingly. @@ -141,12 +167,12 @@ # The +encryption_opts+ can contain any encryption options for the specific security handler # and the common encryption options. # # See: #set_up_encryption (for the common encryption options). def self.set_up_encryption(document, handler_name, **options) - handler = GlobalConfiguration.constantize('encryption.filter_map', handler_name) do - GlobalConfiguration.constantize('encryption.sub_filter_map', handler_name) do + handler = document.config.constantize('encryption.filter_map', handler_name) do + document.config.constantize('encryption.sub_filter_map', handler_name) do raise HexaPDF::EncryptionError, "Could not find the specified security handler" end end handler = handler.new(document) @@ -168,12 +194,12 @@ def self.set_up_decryption(document, **options) dict = document.trailer[:Encrypt] if dict.nil? raise HexaPDF::EncryptionError, "No /Encrypt dictionary found" end - handler = HexaPDF::GlobalConfiguration.constantize('encryption.filter_map', dict[:Filter]) do - HexaPDF::GlobalConfiguration.constantize('encryption.sub_filter_map', dict[:SubFilter]) do + handler = document.config.constantize('encryption.filter_map', dict[:Filter]) do + document.config.constantize('encryption.sub_filter_map', dict[:SubFilter]) do raise HexaPDF::EncryptionError, "Could not find a suitable security handler" end end handler = handler.new(document) @@ -235,12 +261,11 @@ if obj.kind_of?(HexaPDF::Stream) unless string_algorithm == stream_algorithm key = object_key(obj.oid, obj.gen, stream_algorithm) end - obj.raw_stream.filter.unshift(:Encryption) - obj.raw_stream.decode_parms.unshift(key: key, algorithm: stream_algorithm) + obj.data.stream = EncryptedStreamData.new(obj.raw_stream, key, stream_algorithm) end obj end @@ -257,11 +282,18 @@ # Returns a Fiber that encrypts the contents of the given stream object. def encrypt_stream(obj) return obj.stream_encoder if obj.type == :XRef key = object_key(obj.oid, obj.gen, stream_algorithm) - obj.stream_encoder(:Encryption, key: key, algorithm: stream_algorithm) + source = obj.stream_source + result = obj.stream_encoder(source) + if result == source && obj.raw_stream.kind_of?(EncryptedStreamData) && + obj.raw_stream.key == key && obj.raw_stream.algorithm == stream_algorithm + obj.raw_stream.undecrypted_fiber + else + stream_algorithm.encryption_fiber(key, result) + end end # Computes the encryption key and sets up the algorithms for encrypting the document based on # the given options, and returns the corresponding encryption dictionary. # @@ -418,15 +450,15 @@ } end # Returns the class that is used for ARC4 encryption. def arc4_algorithm - @arc4_algorithm ||= HexaPDF::GlobalConfiguration.constantize('encryption.arc4') + @arc4_algorithm ||= document.config.constantize('encryption.arc4') end # Returns the class that is used for AES encryption. def aes_algorithm - @aes_algorithm ||= HexaPDF::GlobalConfiguration.constantize('encryption.aes') + @aes_algorithm ||= document.config.constantize('encryption.aes') end # Returns the class that is used for the identity algorithm which passes back the data as is # without encrypting or decrypting it. def identity_algorithm