Exemple #1
0
    def sign(self, datau, udct, key, cert, othercerts, algomd, hsm,
             timestampurl):
        startdata = len(datau)

        fi = io.BytesIO(datau)

        # read end decrypt
        prev = pdf.PdfFileReader(fi)
        if prev.isEncrypted:
            rc = prev.decrypt(udct["password"])
        else:
            rc = 0

        # digest method must remain unchanged from prevoius signatures
        obj = prev.trailer
        for k in ("/Root", "/Perms", "/DocMDP", "/Reference"):
            if k in obj:
                obj = obj[k]
                if isinstance(obj, po.ArrayObject):
                    obj = obj[0]
                obj = obj.getObject()
            else:
                obj = None
                break
        if obj is not None:
            algomd = obj["/DigestMethod"][1:].lower()

        # produce smaller signatures, but must be signed twice
        aligned = udct.get("aligned", 0)
        if aligned:
            zeros = b"00" * aligned
        else:
            md = getattr(hashlib, algomd)().digest()
            contents = signer.sign(None, key, cert, othercerts, algomd, True,
                                   md, hsm, False, timestampurl)
            zeros = contents.hex().encode("utf-8")

        self.makepdf(prev, udct, algomd, zeros)

        # if document was encrypted, encrypt this version too
        if prev.isEncrypted:
            self.encrypt(prev, udct["password"], rc)
        else:
            self._encrypt_key = None

        # ID[0] is used in password protection, must be unchanged
        ID = prev.trailer.get("/ID", None)
        if ID is None:
            ID = hashlib.md5(repr(time.time()).encode()).digest()
        else:
            ID = ID[0]
            if isinstance(ID, str):
                ID = ID.encode()
        self._ID = po.ArrayObject([
            po.ByteStringObject(ID),
            po.ByteStringObject(
                hashlib.md5(repr(random.random()).encode()).digest()),
        ])

        fo = io.BytesIO()
        self.write(fo, prev, startdata)
        datas = fo.getvalue()

        br = [0, 0, 0, 0]
        bfrom = (b"[ " + b" ".join([WNumberObject.Format] * 4) +
                 b" ]") % tuple(br)

        pdfbr1 = datas.find(zeros)
        pdfbr2 = pdfbr1 + len(zeros)
        br = [
            0,
            startdata + pdfbr1 - 1,
            startdata + pdfbr2 + 1,
            len(datas) - pdfbr2 - 1,
        ]
        bto = b"[%d %d %d %d]" % tuple(br)
        bto += b" " * (len(bfrom) - len(bto))
        assert len(bfrom) == len(bto)
        datas = datas.replace(bfrom, bto, 1)

        md = getattr(hashlib, algomd)()
        md.update(datau)
        b1 = datas[:br[1] - startdata]
        b2 = datas[br[2] - startdata:]
        md.update(b1)
        md.update(b2)
        md = md.digest()

        contents = signer.sign(None, key, cert, othercerts, algomd, True, md,
                               hsm, False, timestampurl)
        contents = contents.hex().encode("utf-8")
        if aligned:
            nb = len(zeros) - len(contents)
            contents += b"0" * nb
        assert len(zeros) == len(contents)

        datas = datas.replace(zeros, contents, 1)

        return datas
Exemple #2
0
    def main(self, fname, password):
        with open(fname, "rb") as fi:
            datau = fi.read()
        startdata = len(datau)

        fi = io.BytesIO(datau)

        prev = pdf.PdfFileReader(fi)
        if prev.isEncrypted:
            rc = prev.decrypt(password)
        else:
            rc = 0

        algomd = "sha1"
        aligned = False

        obj = prev.trailer
        for k in ("/Root", "/Perms", "/DocMDP", "/Reference"):
            if k in obj:
                obj = obj[k]
                if isinstance(obj, po.ArrayObject):
                    obj = obj[0]
                obj = obj.getObject()
            else:
                obj = None
                break
        if obj is not None:
            algomd = obj["/DigestMethod"][1:].lower()

        if aligned:
            zeros = b"0" * 37888
        else:
            md = getattr(hashlib, algomd)().digest()
            contents = self.sign(md, algomd)
            zeros = contents.hex().encode("utf-8")

        self.makepdf(prev, algomd, zeros)

        if prev.isEncrypted:
            self.encrypt(prev, password, rc)
        else:
            self._encrypt_key = None
        ID = prev.trailer.get("/ID", None)
        if ID is None:
            ID = po.ByteStringObject(
                hashlib.md5(repr(time.time()).encode()).digest())
        else:
            ID = ID[0]
        self._ID = po.ArrayObject([
            ID,
            po.ByteStringObject(
                hashlib.md5(repr(random.random()).encode()).digest()),
        ])

        fo = io.BytesIO()
        self.write(fo, prev, startdata)
        datas = fo.getvalue()

        br = [0, 0, 0, 0]
        bfrom = (b"[ " + b" ".join([WNumberObject.Format] * 4) +
                 b" ]") % tuple(br)

        pdfbr1 = datas.find(zeros)
        pdfbr2 = pdfbr1 + len(zeros)
        br = [
            0,
            startdata + pdfbr1 - 1,
            startdata + pdfbr2 + 1,
            len(datas) - pdfbr2 - 1,
        ]
        bto = b"[%d %d %d %d]" % tuple(br)
        bto += b" " * (len(bfrom) - len(bto))
        assert len(bfrom) == len(bto)
        datas = datas.replace(bfrom, bto, 1)

        md = getattr(hashlib, algomd)()
        md.update(datau)
        b1 = datas[:br[1] - startdata]
        b2 = datas[br[2] - startdata:]
        md.update(b1)
        md.update(b2)
        md = md.digest()

        contents = self.sign(md, algomd)
        contents = contents.hex().encode("utf-8")
        if aligned:
            nb = len(zeros) - len(contents)
            contents += b"0" * nb
        datas = datas.replace(zeros, contents, 1)

        fname = fname.replace(".pdf", "-signed-pypdf.pdf")
        with open(fname, "wb") as fp:
            fp.write(datau)
            fp.write(datas)