Class: Epuber::EncryptionHandler
- Inherits:
-
Object
- Object
- Epuber::EncryptionHandler
- Defined in:
- lib/epuber/from_file/encryption_handler.rb
Defined Under Namespace
Classes: EncryptionItem
Constant Summary collapse
- ADOBE_OBFUSCATION =
'http://ns.adobe.com/pdf/enc#RC'
- IDPF_OBFUSCATION =
'http://www.idpf.org/2008/embedding'
Instance Attribute Summary collapse
-
#encryption_items ⇒ Hash<String, EncryptionItem>
readonly
Key is abs file path (from root of EPUB), value is EncryptionItem.
Class Method Summary collapse
-
.decrypt_data(key, data, algorithm) ⇒ Object
Decrypt data with given key and algorithm.
- .find_and_parse_encryption_key(identifiers) ⇒ String?
-
.parse_encryption_file(string) ⇒ Array<EncryptionItem>?
Parse META-INF/encryption.xml file.
-
.parse_idpf_key(raw_unique_identifier) ⇒ String?
Parse IDPF key from unique identifier (main identifier from OPF file).
Instance Method Summary collapse
-
#_prepare_items(encryption_file) ⇒ Hash<String, EncryptionItem>
Prepare encryption items with correct keys.
-
#initialize(encryption_file, opf) ⇒ EncryptionHandler
constructor
A new instance of EncryptionHandler.
- #process_file(path, data) ⇒ Object
Constructor Details
#initialize(encryption_file, opf) ⇒ EncryptionHandler
Returns a new instance of EncryptionHandler.
47 48 49 50 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 47 def initialize(encryption_file, opf) @opf = opf @encryption_items = _prepare_items(encryption_file) end |
Instance Attribute Details
#encryption_items ⇒ Hash<String, EncryptionItem> (readonly)
Returns key is abs file path (from root of EPUB), value is EncryptionItem.
42 43 44 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 42 def encryption_items @encryption_items end |
Class Method Details
.decrypt_data(key, data, algorithm) ⇒ Object
Decrypt data with given key and algorithm
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 67 def self.decrypt_data(key, data, algorithm) is_adobe = algorithm == ADOBE_OBFUSCATION crypt_len = is_adobe ? 1024 : 1040 crypt = data.byteslice(0, crypt_len) .bytes key_cycle = key.bytes .cycle decrypt = crypt.each_with_object([]) { |x, acc| acc << (x ^ key_cycle.next) } .pack('C*') decrypt + data.byteslice(crypt_len..-1) end |
.find_and_parse_encryption_key(identifiers) ⇒ String?
95 96 97 98 99 100 101 102 103 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 95 def self.find_and_parse_encryption_key(identifiers) raw_identifier = identifiers.find do |i| i['scheme']&.downcase == 'uuid' || i.text.strip.start_with?('urn:uuid:') end&.text&.strip return nil unless raw_identifier uuid_str = raw_identifier.sub(/^urn:uuid:/, '') UUIDTools::UUID.parse(uuid_str).raw end |
.parse_encryption_file(string) ⇒ Array<EncryptionItem>?
Parse META-INF/encryption.xml file
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 109 def self.parse_encryption_file(string) doc = Nokogiri::XML(string) doc.remove_namespaces! encryption_node = doc.at_css('encryption') return nil unless encryption_node encryption_node.css('EncryptedData') .map do |encrypted_data_node| algorithm = encrypted_data_node.at_css('EncryptionMethod')['Algorithm'] file_path = encrypted_data_node.at_css('CipherData CipherReference')['URI'] EncryptionItem.new(algorithm, file_path) end end |
.parse_idpf_key(raw_unique_identifier) ⇒ String?
Parse IDPF key from unique identifier (main identifier from OPF file)
85 86 87 88 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 85 def self.parse_idpf_key(raw_unique_identifier) key = raw_unique_identifier.strip.gsub(/[\u0020\u0009\u000d\u000a]/, '') Digest::SHA1.digest(key) end |
Instance Method Details
#_prepare_items(encryption_file) ⇒ Hash<String, EncryptionItem>
Prepare encryption items with correct keys
131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 131 def _prepare_items(encryption_file) idpf_key = EncryptionHandler.parse_idpf_key(@opf.raw_unique_identifier) adobe_key = EncryptionHandler.find_and_parse_encryption_key(@opf.identifiers) items = EncryptionHandler.parse_encryption_file(encryption_file) items.each do |i| if i.algorithm == EncryptionHandler::IDPF_OBFUSCATION i.key = idpf_key elsif i.algorithm == EncryptionHandler::ADOBE_OBFUSCATION i.key = adobe_key end end items.map { |i| [i.file_path, i] }.to_h end |
#process_file(path, data) ⇒ Object
54 55 56 57 58 59 |
# File 'lib/epuber/from_file/encryption_handler.rb', line 54 def process_file(path, data) enc_item = @encryption_items[path] data = EncryptionHandler.decrypt_data(enc_item.key, data, enc_item.algorithm) if enc_item data end |