示例#1
0
    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)
示例#2
0
    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)
示例#3
0
 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)
示例#4
0
 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)