def process_encryption(self): fonts = {} enc = self.parsed('META-INF/encryption.xml') for em in enc.xpath( '//*[local-name()="EncryptionMethod" and @Algorithm]'): alg = em.get('Algorithm') if alg not in {ADOBE_OBFUSCATION, IDPF_OBFUSCATION}: raise DRMError() try: cr = em.getparent().xpath( 'descendant::*[local-name()="CipherReference" and @URI]' )[0] except (IndexError, ValueError, KeyError): continue name = self.href_to_name(cr.get('URI')) path = self.name_path_map.get(name, None) if path is not None: fonts[name] = alg if not fonts: return package_id = raw_unique_identifier = idpf_key = None for attrib, val in self.opf.attrib.iteritems(): if attrib.endswith('unique-identifier'): package_id = val break if package_id is not None: for elem in self.opf_xpath('//*[@id=%r]' % package_id): if elem.text: raw_unique_identifier = elem.text break if raw_unique_identifier is not None: idpf_key = raw_unique_identifier idpf_key = re.sub(u'\u0020\u0009\u000d\u000a', u'', idpf_key) idpf_key = hashlib.sha1(idpf_key.encode('utf-8')).digest() key = None for item in self.opf_xpath('//*[local-name()="metadata"]/*' '[local-name()="identifier"]'): scheme = None for xkey in item.attrib.keys(): if xkey.endswith('scheme'): scheme = item.get(xkey) if (scheme and scheme.lower() == 'uuid') or \ (item.text and item.text.startswith('urn:uuid:')): try: key = bytes(item.text).rpartition(':')[-1] key = uuid.UUID(key).bytes except: self.log.exception('Failed to parse obfuscation key') key = None for font, alg in fonts.iteritems(): tkey = key if alg == ADOBE_OBFUSCATION else idpf_key if not tkey: raise InvalidBook('Failed to find obfuscation key') raw = self.raw_data(font, decode=False) raw = decrypt_font_data(tkey, raw, alg) with self.open(font, 'wb') as f: f.write(raw) self.obfuscated_fonts[font] = (alg, tkey)
def process_encryption(self): fonts = {} enc = self.parsed('META-INF/encryption.xml') for em in enc.xpath('//*[local-name()="EncryptionMethod" and @Algorithm]'): alg = em.get('Algorithm') if alg not in {ADOBE_OBFUSCATION, IDPF_OBFUSCATION}: raise DRMError() try: cr = em.getparent().xpath('descendant::*[local-name()="CipherReference" and @URI]')[0] except (IndexError, ValueError, KeyError): continue name = self.href_to_name(cr.get('URI')) path = self.name_path_map.get(name, None) if path is not None: fonts[name] = alg if not fonts: return package_id = raw_unique_identifier = idpf_key = None for attrib, val in self.opf.attrib.iteritems(): if attrib.endswith('unique-identifier'): package_id = val break if package_id is not None: for elem in self.opf_xpath('//*[@id=%r]'%package_id): if elem.text: raw_unique_identifier = elem.text break if raw_unique_identifier is not None: idpf_key = raw_unique_identifier idpf_key = re.sub(u'\u0020\u0009\u000d\u000a', u'', idpf_key) idpf_key = hashlib.sha1(idpf_key.encode('utf-8')).digest() key = None for item in self.opf_xpath('//*[local-name()="metadata"]/*' '[local-name()="identifier"]'): scheme = None for xkey in item.attrib.keys(): if xkey.endswith('scheme'): scheme = item.get(xkey) if (scheme and scheme.lower() == 'uuid') or \ (item.text and item.text.startswith('urn:uuid:')): try: key = bytes(item.text).rpartition(':')[-1] key = uuid.UUID(key).bytes except: self.log.exception('Failed to parse obfuscation key') key = None for font, alg in fonts.iteritems(): tkey = key if alg == ADOBE_OBFUSCATION else idpf_key if not tkey: raise InvalidBook('Failed to find obfuscation key') raw = self.raw_data(font, decode=False) raw = decrypt_font_data(tkey, raw, alg) with self.open(font, 'wb') as f: f.write(raw) self.obfuscated_fonts[font] = (alg, tkey)
def commit(self, outpath=None, keep_parsed=False): super(EpubContainer, self).commit(keep_parsed=keep_parsed) restore_fonts = {} for name in self.obfuscated_fonts: if name not in self.name_path_map: continue alg, key = self.obfuscated_fonts[name] # Decrypting and encrypting are the same operation (XOR with key) restore_fonts[name] = data = self.raw_data(name, decode=False) with self.open(name, 'wb') as f: f.write(decrypt_font_data(key, data, alg)) if outpath is None: outpath = self.pathtoepub from calibre.ebooks.tweak import zip_rebuilder with open(join(self.root, 'mimetype'), 'wb') as f: f.write(guess_type('a.epub')) zip_rebuilder(self.root, outpath) for name, data in restore_fonts.iteritems(): with self.open(name, 'wb') as f: f.write(data)