├── tests ├── __init__.py └── fixtures │ ├── pdf.pdf │ ├── pdf-XRef.pdf │ ├── pdf-true.pdf │ ├── pdf-encrypted.pdf │ ├── pdf-XRefStream.pdf │ ├── plain-unsigned.txt │ ├── smime-unsigned.txt │ └── .gitignore ├── docs ├── .gitignore ├── modules.rst ├── endesive.xades.rst ├── index.rst ├── endesive.plain.rst ├── Makefile ├── endesive.pdf.rst ├── endesive.rst ├── make.bat ├── endesive.email.rst └── conf.py ├── endesive ├── pdf │ ├── PyPDF2_annotate │ │ ├── config │ │ │ ├── __init__.py │ │ │ ├── location.py │ │ │ ├── constants.py │ │ │ ├── graphics_state.py │ │ │ └── metadata.py │ │ ├── fonts │ │ │ ├── __init__.py │ │ │ └── Helvetica.ttf │ │ ├── util │ │ │ ├── __init__.py │ │ │ ├── font_metrics.py │ │ │ └── text.py │ │ ├── annotations │ │ │ └── __init__.py │ │ ├── __init__.py │ │ └── pdfrw.py │ ├── PyPDF2 │ │ ├── _version.py │ │ └── __init__.py │ ├── __init__.py │ ├── fpdf │ │ ├── __init__.py │ │ ├── php.py │ │ └── py3k.py │ └── pdf.py ├── xades │ └── __init__.py ├── plain │ ├── __init__.py │ ├── verify.py │ └── sign.py ├── email │ ├── __init__.py │ ├── verify.py │ ├── sign.py │ └── decrypt.py └── __init__.py ├── examples ├── hsm ├── ca │ ├── 98315084947916818053205948128474780334601525706 │ ├── 170647371793814353188311742751744469876499188224 │ ├── 248075908521160111375160830087228812224077410680 │ ├── 288528155615202608532924619510015678088367985326 │ ├── 571131681754382479759372987552620622065870021143 │ ├── demo2_user1.p12 │ ├── demo2_user2.p12 │ ├── demo2_user3.p12 │ ├── demo2_user1.crt.pem.cer │ ├── demo2_user2.crt.pem.cer │ ├── demo2_user3.crt.pem.cer │ ├── demo2_ca.root.crt.pem.cer │ ├── demo2_ca.sub.crt.pem.cer │ ├── demo2_user1.pub.pem │ ├── demo2_user2.pub.pem │ ├── demo2_user3.pub.pem │ ├── demo2_ca.root.crt.pem │ ├── demo2_ca.sub.crt.pem │ ├── demo2_user1.crt.pem │ ├── demo2_user2.crt.pem │ ├── demo2_user3.crt.pem │ ├── demo2_user1.key.pem │ ├── demo2_user2.key.pem │ └── demo2_user3.key.pem ├── pdf-buggy.pdf ├── DejaVuSans.ttf ├── pdf-acrobat.pdf ├── pdf-linearized.pdf ├── signature_test.png ├── pdf_forms │ └── blank_form.pdf ├── test-SHA256_RSA-signed-cms.pdf ├── test-signed-cms-hsm-Google.pdf ├── pdf-adobe-webcapture-x509.rsa_sha1.pdf ├── pdf-sign-cms-pfx ├── cert-install ├── certum │ └── xml-certum ├── hsm-pkcs ├── pdf-alter.py ├── java-compile ├── .gitignore ├── pdf-verifier-pyhanko ├── certum.py ├── kir.py ├── plain-make.py ├── smime-make.py ├── pdf-annotate.py ├── pdf-encrypt.py ├── mypy.ini ├── pdf-make-wkhtml.py ├── plain-sign-attr.py ├── smime-sign-attr.py ├── plain-sign-noattr.py ├── smime-sign-noattr.py ├── plain-sign-pss.py ├── smime-sign-pss.py ├── pdfbox.py ├── t-ocsp-show.py ├── smime-encrypt.py ├── pdfboxValidate.py ├── xml-xmlsigner-verify.py ├── cert-info-pem.py ├── xml-xmlsigner-enveloping.py ├── smime-verify.py ├── smime-decrypt.py ├── plain-verify.py ├── xml-xmlsigner-enveloped.py ├── pdf-sign-fpdf.py ├── smime-sign-attr-custom.py ├── pdf-dump.py ├── pdfviewer.py ├── test-certificate-googleHSM.crt.pem ├── cert-info-p12.py ├── pdf-timestamp-cms.py ├── plain-openssl.sh ├── pdf-make.py ├── pdf-sign-cms-pil.py ├── pdf-sign-cms-twice-1.py ├── pdf-sign-cms-twice-2.py ├── pdf-sign-cms-twice-end.py ├── pdf-sign-cms.py ├── pdf-sign-cms-m32-unizeto.py ├── pdf-sign-cms-m32-actalis.py ├── pdf-verify.py ├── signature_appearances │ ├── signature_img.py │ ├── signature.py │ ├── signature_appearance.py │ ├── signature-existing-field.py │ └── signature_manual.py ├── pdf-sign-cms-hsm-windows.py ├── pdf-verifier.py ├── nccert2016.crt.pem ├── pdf-sign-cms-ltv.py ├── pdf-verify-hsm.py ├── csmimersaca.cer.pem ├── t-ocsp-get.py ├── pdf-verify-rsa_sha1.py ├── pdf-sign-cms-hsm-google.py ├── pdf-dump-dss.py ├── cert-make-hsm.py ├── t-ts-get.py ├── smime-openssl.sh ├── pdf-dump-offsets.py ├── xml-make.py ├── xml-hsm-softhsm2-enveloped.py ├── xml-hsm-softhsm2-enveloping.py ├── pdf-sign-cms-hsm-certum.py ├── pdf-sign-cms-hsm-kir.py ├── t-rsa-sha256.py ├── pdf-sign-cms-hash-sign.py ├── cert-info-hsm.py ├── xml-hsm-certum-enveloped.py ├── pdf-sign-cms-hash.py ├── xml-hsm-certum-enveloping.py └── pdf-sign-cms-hsm.py ├── MANIFEST.in ├── Makefile ├── LICENSE ├── LICENSE.pdf-annotate ├── LICENSE.pypdf2 ├── pyproject.toml └── .gitignore /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _*/ 2 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/fonts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/util/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/annotations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /endesive/xades/__init__.py: -------------------------------------------------------------------------------- 1 | from .bes import BES 2 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.26.0' 2 | -------------------------------------------------------------------------------- /examples/hsm: -------------------------------------------------------------------------------- 1 | SOFTHSM2_CONF=softhsm2.conf softhsm2-util $* 2 | -------------------------------------------------------------------------------- /examples/ca/98315084947916818053205948128474780334601525706: -------------------------------------------------------------------------------- 1 | demo2_user1.crt.pem -------------------------------------------------------------------------------- /examples/ca/170647371793814353188311742751744469876499188224: -------------------------------------------------------------------------------- 1 | demo2_ca.root.crt.pem -------------------------------------------------------------------------------- /examples/ca/248075908521160111375160830087228812224077410680: -------------------------------------------------------------------------------- 1 | demo2_user3.crt.pem -------------------------------------------------------------------------------- /examples/ca/288528155615202608532924619510015678088367985326: -------------------------------------------------------------------------------- 1 | demo2_user2.crt.pem -------------------------------------------------------------------------------- /examples/ca/571131681754382479759372987552620622065870021143: -------------------------------------------------------------------------------- 1 | demo2_ca.sub.crt.pem -------------------------------------------------------------------------------- /endesive/plain/__init__.py: -------------------------------------------------------------------------------- 1 | from .sign import sign 2 | from .verify import verify 3 | -------------------------------------------------------------------------------- /examples/pdf-buggy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/pdf-buggy.pdf -------------------------------------------------------------------------------- /tests/fixtures/pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/tests/fixtures/pdf.pdf -------------------------------------------------------------------------------- /examples/DejaVuSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/DejaVuSans.ttf -------------------------------------------------------------------------------- /examples/pdf-acrobat.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/pdf-acrobat.pdf -------------------------------------------------------------------------------- /examples/ca/demo2_user1.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user1.p12 -------------------------------------------------------------------------------- /examples/ca/demo2_user2.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user2.p12 -------------------------------------------------------------------------------- /examples/ca/demo2_user3.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user3.p12 -------------------------------------------------------------------------------- /examples/pdf-linearized.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/pdf-linearized.pdf -------------------------------------------------------------------------------- /examples/signature_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/signature_test.png -------------------------------------------------------------------------------- /tests/fixtures/pdf-XRef.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/tests/fixtures/pdf-XRef.pdf -------------------------------------------------------------------------------- /tests/fixtures/pdf-true.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/tests/fixtures/pdf-true.pdf -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | endesive 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | endesive 8 | -------------------------------------------------------------------------------- /endesive/pdf/__init__.py: -------------------------------------------------------------------------------- 1 | from . import cms 2 | from . import pdf 3 | from .verify import PDFVerifier, verify 4 | -------------------------------------------------------------------------------- /tests/fixtures/pdf-encrypted.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/tests/fixtures/pdf-encrypted.pdf -------------------------------------------------------------------------------- /examples/ca/demo2_user1.crt.pem.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user1.crt.pem.cer -------------------------------------------------------------------------------- /examples/ca/demo2_user2.crt.pem.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user2.crt.pem.cer -------------------------------------------------------------------------------- /examples/ca/demo2_user3.crt.pem.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_user3.crt.pem.cer -------------------------------------------------------------------------------- /examples/pdf_forms/blank_form.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/pdf_forms/blank_form.pdf -------------------------------------------------------------------------------- /tests/fixtures/pdf-XRefStream.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/tests/fixtures/pdf-XRefStream.pdf -------------------------------------------------------------------------------- /examples/ca/demo2_ca.root.crt.pem.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_ca.root.crt.pem.cer -------------------------------------------------------------------------------- /examples/ca/demo2_ca.sub.crt.pem.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/ca/demo2_ca.sub.crt.pem.cer -------------------------------------------------------------------------------- /examples/test-SHA256_RSA-signed-cms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/test-SHA256_RSA-signed-cms.pdf -------------------------------------------------------------------------------- /examples/test-signed-cms-hsm-Google.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/test-signed-cms-hsm-Google.pdf -------------------------------------------------------------------------------- /examples/pdf-adobe-webcapture-x509.rsa_sha1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/examples/pdf-adobe-webcapture-x509.rsa_sha1.pdf -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/fonts/Helvetica.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/endesive/HEAD/endesive/pdf/PyPDF2_annotate/fonts/Helvetica.ttf -------------------------------------------------------------------------------- /examples/pdf-sign-cms-pfx: -------------------------------------------------------------------------------- 1 | ./pdf-sign-cms-pfx.py -d pdf-signed-cms-pfx.pdf ~/Dokumenty/m32/ssl/actalis/certificate_s_mime.p12 "1AR0uaCd=vqaQww12&" pdf.pdf 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE.pyfpdf 2 | include LICENSE.pypdf2 3 | include LICENSE.pdf-annotate 4 | include endesive/pdf/PyPDF2_annotate/fonts/Helvetica.ttf 5 | -------------------------------------------------------------------------------- /examples/cert-install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # sudo ./cert-install 3 | cp ca/demo2_ca.root.crt.pem /usr/share/ca-certificates/mozilla/ 4 | update-ca-certificates --default 5 | -------------------------------------------------------------------------------- /examples/certum/xml-certum: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /devel/bin/proCertumSmartSign-8.1.15/proCertumSmartSign.sh \ 3 | $* 4 | #--configuration $1.config \ 5 | #--sign $1 \ 6 | -------------------------------------------------------------------------------- /endesive/email/__init__.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | from .decrypt import decrypt 3 | from .encrypt import encrypt 4 | from .sign import sign 5 | from .verify import verify 6 | -------------------------------------------------------------------------------- /examples/hsm-pkcs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export OPENSC_DEBUG=9 3 | export PYKCS11LIB=/usr/lib/softhsm/libsofthsm2.so 4 | export SOFTHSM_CONF=./softhsm2.conf 5 | pkcs11-tool --module $PYKCS11LIB $* 6 | -------------------------------------------------------------------------------- /endesive/__init__.py: -------------------------------------------------------------------------------- 1 | """Python ENDESIVE library.""" 2 | 3 | __author__ = 'Grzegorz Makarewicz' 4 | __license__ = 'MIT' 5 | __version__ = '2.19.2' 6 | 7 | __all__ = [__author__, __license__, __version__] 8 | -------------------------------------------------------------------------------- /tests/fixtures/plain-unsigned.txt: -------------------------------------------------------------------------------- 1 | Witam, 2 | 3 | Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. 4 | Mam nadzieję, że będzie dla Ciebie użyteczna. 5 | 6 | Pozdrawiam, 7 | Grzegorz Makarewicz 8 | -------------------------------------------------------------------------------- /tests/fixtures/smime-unsigned.txt: -------------------------------------------------------------------------------- 1 | Witam, 2 | 3 | Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. 4 | Mam nadzieję, że będzie dla Ciebie użyteczna. 5 | 6 | Pozdrawiam, 7 | Grzegorz Makarewicz 8 | -------------------------------------------------------------------------------- /examples/pdf-alter.py: -------------------------------------------------------------------------------- 1 | import pymupdf 2 | doc = pymupdf.open('pdf-acrobat.pdf') 3 | page = doc[0] 4 | rects = page.search_for("world") 5 | page.add_highlight_annot(rects) 6 | doc.save("pdf-acrobat-modified.pdf") 7 | -------------------------------------------------------------------------------- /examples/java-compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | thisdir=`dirname $0` 3 | jars="$thisdir" 4 | addjar(){ 5 | jars="$jars:$1" 6 | } 7 | for fname in $thisdir/java/*.jar; do 8 | addjar $fname 9 | done 10 | javac -cp $jars $1 -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2/__init__.py: -------------------------------------------------------------------------------- 1 | from .pdf import PdfFileReader, PdfFileWriter 2 | from .merger import PdfFileMerger 3 | from .pagerange import PageRange, parse_filename_page_ranges 4 | from ._version import __version__ 5 | __all__ = ["pdf", "PdfFileMerger"] 6 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | *.pem 2 | *.crt 3 | *.der 4 | *.p7s 5 | *.json 6 | softhsm2/ 7 | softhsm2.conf 8 | signature_appearances/endesive/ 9 | 10 | t-ocsp-crl.der 11 | t-ocsp-issuer.der 12 | t-ocsp-req.bin 13 | t-ocsp-resp.bin 14 | t-ts-req.bin 15 | t-ts-resp.bin 16 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .annotator import PdfAnnotator 3 | from .config.appearance import Appearance 4 | from .config.location import Location 5 | from .config.metadata import Metadata 6 | 7 | 8 | __all__ = ['PdfAnnotator', 'Appearance', 'Location', 'Metadata'] 9 | -------------------------------------------------------------------------------- /examples/pdf-verifier-pyhanko: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | full() { 4 | vpy3 pyhanko \ 5 | --verbose \ 6 | sign validate \ 7 | --pretty-print \ 8 | $* 9 | } 10 | 11 | fast() { 12 | full \ 13 | --no-revocation-check \ 14 | $* 15 | } 16 | 17 | 18 | #pdf-verifier-pyhanko fast pdf-signed-cms.pdf 19 | #pdf-verifier-pyhanko fast pdf-signed-cms-m32-unizeto.pdf 20 | $* 21 | -------------------------------------------------------------------------------- /docs/endesive.xades.rst: -------------------------------------------------------------------------------- 1 | endesive.xades package 2 | ====================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | endesive.xades.bes module 8 | ------------------------- 9 | 10 | .. automodule:: endesive.xades.bes 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: endesive.xades 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /examples/certum.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.platform == "win32": 4 | dllpath = r"c:\windows\system32\cryptoCertum3PKCS.dll" 5 | else: 6 | import ctypes as ct 7 | if 1: 8 | openssl_1_1 = [ 9 | ct.CDLL('/usr/lib/x86_64-linux-gnu/libcrypto.so', ct.RTLD_GLOBAL), 10 | ct.CDLL('/usr/lib/x86_64-linux-gnu/libssl.so', ct.RTLD_GLOBAL), 11 | ] 12 | dllpath = '/devel/lib/pkcs11libs/libcryptoCertum3PKCS.so' 13 | -------------------------------------------------------------------------------- /examples/kir.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.platform == "win32": 4 | dllpath = r"c:\windows\system32\cryptoCertum3PKCS.dll" 5 | else: 6 | import ctypes as ct 7 | if 0: 8 | openssl_1_1 = [ 9 | ct.CDLL('/usr/lib/x86_64-linux-gnu/libcrypto.so', ct.RTLD_GLOBAL), 10 | ct.CDLL('/usr/lib/x86_64-linux-gnu/libssl.so', ct.RTLD_GLOBAL), 11 | ] 12 | dllpath = '/devel/lib/pkcs11libs/libCCGraphiteP11.2.0.5.6.so' 13 | -------------------------------------------------------------------------------- /examples/plain-make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import io 4 | 5 | 6 | def main(): 7 | io.open('plain-unsigned.txt', 'wt', encoding='utf-8').write('''\ 8 | Witam, 9 | 10 | Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. 11 | Mam nadzieję, że będzie dla Ciebie użyteczna. 12 | 13 | Pozdrawiam, 14 | Grzegorz Makarewicz 15 | ''' 16 | ) 17 | 18 | 19 | main() 20 | -------------------------------------------------------------------------------- /examples/smime-make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import io 4 | 5 | 6 | def main(): 7 | io.open('smime-unsigned.txt', 'wt', encoding='utf-8').write('''\ 8 | Witam, 9 | 10 | Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. 11 | Mam nadzieję, że będzie dla Ciebie użyteczna. 12 | 13 | Pozdrawiam, 14 | Grzegorz Makarewicz 15 | ''' 16 | ) 17 | 18 | 19 | main() 20 | -------------------------------------------------------------------------------- /examples/pdf-annotate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | from pdf_annotate import PdfAnnotator, Location, Appearance 3 | 4 | annotationtext = "some text" 5 | 6 | a = PdfAnnotator("pdf.pdf") 7 | a.add_annotation( 8 | "text", 9 | Location(x1=50, y1=50, x2=200, y2=100, page=0), 10 | Appearance( 11 | fill=(0, 0, 0), 12 | stroke_width=1, 13 | wrap_text=True, 14 | font_size=12, 15 | content=annotationtext, 16 | ), 17 | ) 18 | a.write("pdf-a.pdf") 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | rm -rf tests/fixtures/softhsm2 tests/fixtures/softhsm2.conf tests/fixtures/cert-* tests/fixtures/demo2_* 3 | vpython3 -m coverage run --omit "endesive/pdf/PyPDF2/*","endesive/pdf/PyPDF2_annotate/*","endesive/pdf/fpdf/*","endesive/pdf/pdf.py","/usr/lib/*" -m unittest discover tests 4 | vpy3-coverage3 report -m 5 | 6 | mypy: 7 | mypy endesive --ignore-missing-imports --check-untyped --strict 8 | 9 | docs: 10 | sphinx-apidoc -o docs ./endesive 11 | 12 | .PHONY: test mypy docs 13 | -------------------------------------------------------------------------------- /endesive/pdf/fpdf/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | "FPDF for python" 5 | 6 | __license__ = "LGPL 3.0" 7 | __version__ = "1.7.2" 8 | 9 | from .fpdf import FPDF, FPDF_FONT_DIR, FPDF_VERSION, SYSTEM_TTFONTS, set_global, FPDF_CACHE_MODE, FPDF_CACHE_DIR 10 | try: 11 | from .html import HTMLMixin 12 | except ImportError: 13 | import warnings 14 | warnings.warn("web2py gluon package not installed, required for html2pdf") 15 | 16 | from .template import Template 17 | -------------------------------------------------------------------------------- /examples/ca/demo2_user1.pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0+yOafFFG0d+aP3yFOxm 3 | l5M+vgl/prN4fcT2ctSFIBom+0Uc68OcMC9uR9CG+xFbqXgUUn4hxBLAutaV8FCR 4 | v7KGMvAjDX+5tf8Mm/GPqp7gVXu662UO/0/dSrpN5XwpJw7BQhCicd5dNY0pRFna 5 | 0cm0Un2sZEeKtOTqKy65L4m/WA/8NorMVQX/DifwdiHvCMje88Mt5Vozz5tTnPBi 6 | Qaj6Ccdn3rPhtfInyU6AfpiK7cm9RyjnQRtkCs0EElQcMWnjRBDL22hK49AJIDqs 7 | xD43v/Gj1arSkl1oOMwYOIdS4xBx0jMQtI1XqzBQSR0VNL5jmgZtgzB9SKnwUYtt 8 | EwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /examples/ca/demo2_user2.pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8073kmNkCk7sVZiZ+H2 3 | MK82dEr/Yt+FTes65/mnOnBpoXymjXgTFJy67UbGdbFITfrDTk4HbqVnmP7Zbe/B 4 | SV2P7snPcleEAQ0acQi7x+q3I3sW8E394HgDtQAPJ5kUf2sHl4ICpPOLBYNdkH1f 5 | TMYFTQDecbAU8DT6vxBLg+2q/gM7Z/HXINvxpGWegG9Lbu410BMMtuZV1iimVu2r 6 | 27KCu2g6QfpgCFjdtcIVzG06iILI8e2kDjptOQNoOVM1jf3glb1ZQ3CBYQcRpR3o 7 | hdq/bJZGUqAtPJ3mqipUy4MlfJfLHB5868iP8FT9Kb4N6jasa+d9paKzov5hnXB7 8 | nQIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /examples/ca/demo2_user3.pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA503JuzWktdrTvabFqDEU 3 | T8TlIw5t/MbJko9CuxpZ30ixv9iqiLaqdB7mWk0gzSrKce8oX0y+NIVtnA50+LQG 4 | E9xu0hvc/p9/6btcMpbtSyXgu6XRSYGsrNzPivbUPSOsGO/qbsI4h62LuEmap7TT 5 | K7lzwIV8vU8ti4Ujvt6DAfgLSvNlF7xXLJMPSNSCbvVTLzp7ya+tRkF8QzpBqWxp 6 | pjUPF6T8Jj/O5ji8otHFKjd3mhJgkU7tCpms3k1ZnE8OIGKlq/lLKoreV41ySmvz 7 | LNSkxlSrJDiBFaNyCt4WVVQpe/ZrBMUdgJwKed6AcwDqjySrMsEzT4B3TaJ9AkAn 8 | uwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /examples/pdf-encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | from PyPDF2 import PdfFileReader, PdfFileWriter 5 | 6 | fname = "pdf.pdf" 7 | with open(fname, "rb") as in_file: 8 | input_pdf = PdfFileReader(in_file) 9 | 10 | output_pdf = PdfFileWriter() 11 | output_pdf.appendPagesFromReader(input_pdf) 12 | output_pdf.encrypt("1234", "1234") 13 | 14 | fname = fname.replace('.pdf', '-encrypted.pdf') 15 | with open(fname, "wb") as out_file: 16 | output_pdf.write(out_file) 17 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. endesive documentation master file, created by 2 | sphinx-quickstart on Thu Jun 19 22:09:04 2025. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | endesive documentation 7 | ====================== 8 | 9 | Add your content using ``reStructuredText`` syntax. See the 10 | `reStructuredText `_ 11 | documentation for details. 12 | 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :caption: Contents: 17 | 18 | modules 19 | -------------------------------------------------------------------------------- /examples/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | 3 | ;strict = True 4 | ;strict_bytes = True 5 | local_partial_types = True 6 | ;disallow_any_unimported = True 7 | ;show_traceback = True 8 | pretty = True 9 | always_false = MYPYC 10 | plugins = mypy.plugins.proper_plugin 11 | python_version = 3.11 12 | ;exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/ 13 | ;enable_error_code = ignore-without-code,redundant-expr 14 | ;enable_incomplete_feature = PreciseTupleTypes 15 | show_error_code_links = True 16 | ;try_statements = 25 17 | 18 | [mypy-mypy.*] 19 | # TODO: enable for `mypyc` and other files as well 20 | warn_unreachable = True 21 | -------------------------------------------------------------------------------- /docs/endesive.plain.rst: -------------------------------------------------------------------------------- 1 | endesive.plain package 2 | ====================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | endesive.plain.sign module 8 | -------------------------- 9 | 10 | .. automodule:: endesive.plain.sign 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | endesive.plain.verify module 16 | ---------------------------- 17 | 18 | .. automodule:: endesive.plain.verify 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: endesive.plain 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /examples/pdf-make-wkhtml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | from mako.template import Template 3 | from mako.runtime import Context 4 | from io import StringIO 5 | 6 | raw_html = '

Hello, ${name}!

' 7 | data = {'name': 'Tapan'} 8 | pdf_name = 'pdf-wkhtml.pdf' 9 | 10 | mytemplate = Template(raw_html) 11 | buf = StringIO() 12 | ctx = Context(buf, **data) 13 | mytemplate.render_context(ctx) 14 | html = buf.getvalue() 15 | 16 | import pdfkit 17 | 18 | WKHTMLTOPDF_OPTIONS = { 19 | 'page-size': 'A4', 20 | 'encoding': 'UTF-8', 21 | } 22 | 23 | pdfkit.from_string( 24 | html, 25 | pdf_name, 26 | options=WKHTMLTOPDF_OPTIONS 27 | ) 28 | -------------------------------------------------------------------------------- /examples/plain-sign-attr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import plain 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('plain-unsigned.txt', 'rb').read() 12 | datas = plain.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha256', 15 | attrs=True 16 | ) 17 | open('plain-signed-attr.txt', 'wb').write(datas) 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /examples/smime-sign-attr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import email 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('smime-unsigned.txt', 'rb').read() 12 | datas = email.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha256', 15 | attrs=True 16 | ) 17 | open('smime-signed-attr.txt', 'wb').write(datas) 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /examples/plain-sign-noattr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import plain 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('plain-unsigned.txt', 'rb').read() 12 | datas = plain.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha256', 15 | attrs=False 16 | ) 17 | open('plain-signed-noattr.txt', 'wb').write(datas) 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /examples/smime-sign-noattr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import email 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('smime-unsigned.txt', 'rb').read() 12 | datas = email.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha256', 15 | attrs=False 16 | ) 17 | open('smime-signed-noattr.txt', 'wb').write(datas) 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /examples/plain-sign-pss.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import plain 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('plain-unsigned.txt', 'rb').read() 12 | datas = plain.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha512', 15 | attrs=True, 16 | pss=True 17 | ) 18 | open('plain-signed-pss.txt', 'wb').write(datas) 19 | 20 | 21 | main() 22 | -------------------------------------------------------------------------------- /examples/smime-sign-pss.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import email 6 | 7 | 8 | def main(): 9 | with open('ca/demo2_user1.p12', 'rb') as fp: 10 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 11 | datau = open('smime-unsigned.txt', 'rb').read() 12 | datas = email.sign(datau, 13 | p12[0], p12[1], p12[2], 14 | 'sha512', 15 | attrs=True, 16 | pss=True 17 | ) 18 | open('smime-signed-pss.txt', 'wb').write(datas) 19 | 20 | 21 | main() 22 | -------------------------------------------------------------------------------- /examples/pdfbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import os 3 | #os.environ['JAVA_HOME'] = '/usr/lib/jvm/msopenjdk-21-amd64/' 4 | os.environ['JVM_PATH'] = '/usr/lib/jvm/msopenjdk-21-amd64/lib/server/libjvm.so' 5 | import sys 6 | import jnius_config 7 | 8 | PATH=['.'] 9 | def walk(top): 10 | todo = [] 11 | for fname in os.listdir(top): 12 | fqname = os.path.join(top, fname) 13 | if os.path.isdir(fqname): 14 | todo.append(fqname) 15 | elif fname.split('.')[-1] == 'jar': 16 | PATH.append(fqname) 17 | for fqname in todo: 18 | walk(fqname) 19 | 20 | walk('/devel/lib/java/pdfbox') 21 | jnius_config.set_classpath(*PATH) 22 | 23 | 24 | import jnius 25 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /examples/t-ocsp-show.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from asn1crypto import ocsp as aocsp 4 | from cryptography.x509 import ocsp 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives import hashes, serialization 7 | from cryptography.hazmat.primitives.asymmetric import padding, utils 8 | from cryptography.hazmat.primitives.serialization import pkcs12 9 | 10 | 11 | def main(): 12 | print("*" * 20, "req") 13 | data = open("t-ocsp-req.bin", "rb").read() 14 | ocspr = aocsp.OCSPRequest.load(data) 15 | print(ocspr.debug()) 16 | 17 | print("*" * 20, "resp") 18 | data = open("t-ocsp-resp.bin", "rb").read() 19 | ocspresp = aocsp.OCSPResponse.load(data) 20 | print(ocspresp.debug()) 21 | 22 | 23 | main() 24 | -------------------------------------------------------------------------------- /examples/smime-encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography import x509 4 | from cryptography.hazmat import backends 5 | from endesive import email, signer 6 | 7 | 8 | def load_cert(relative_path): 9 | with open(relative_path, 'rb') as f: 10 | return x509.load_pem_x509_certificate(f.read(), backends.default_backend()) 11 | 12 | 13 | def main(): 14 | certs = ( 15 | load_cert('ca/demo2_user1.crt.pem'), 16 | ) 17 | datau = open('smime-unsigned.txt', 'rb').read() 18 | datae = email.encrypt(datau, certs, 'aes256_ofb') 19 | open('smime-encrypted.txt', 'wt').write(datae) 20 | datae = email.encrypt(datau, certs, 'aes256_ofb', True) 21 | open('smime-encrypted-oaep.txt', 'wt').write(datae) 22 | 23 | 24 | main() 25 | -------------------------------------------------------------------------------- /examples/pdfboxValidate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import pdfbox 4 | from jnius import autoclass 5 | 6 | pdfname = 'pdf.pdf' 7 | if len(sys.argv) > 1: 8 | pdfname = sys.argv[1] 9 | signature = autoclass('org.apache.pdfbox.examples.examples.ShowSignature') 10 | signature.showSignature('', pdfname) 11 | parser.parse() 12 | #org.apache.pdfbox.preflight.PreflightDocument 13 | document = parser.getPreflightDocument() 14 | document.validate() 15 | result = document.getResult() 16 | document.close() 17 | if result.isValid(): 18 | print("The file:{} is a valid PDF/A-1b file".format(pdfname)) 19 | else: 20 | print("The file: {} is not valid, error(s) :".format(pdfname)) 21 | for error in result.getErrorsList(): 22 | print(error.getErrorCode(), " : ", error.getDetails()) 23 | -------------------------------------------------------------------------------- /examples/xml-xmlsigner-verify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | from lxml import etree 5 | import signxml 6 | 7 | if sys.argv[1:]: 8 | fname = sys.argv[1] 9 | else: 10 | fname = "xml-xmlsigner-enveloped.xml" 11 | #fname = "xml-xmlsigner-enveloping.xml" 12 | #fname = 'xml-xades-bes-enveloped.xml' 13 | data = open(fname, "rb").read() 14 | 15 | signed_root = etree.fromstring(data) 16 | 17 | verified_data = ( 18 | signxml.XMLVerifier().verify(signed_root, ca_pem_file="ca/demo2_ca.root.crt.pem").signed_xml 19 | ) 20 | 21 | xml = etree.tostring( 22 | verified_data, 23 | encoding="UTF-8", 24 | xml_declaration=True, 25 | standalone=False, 26 | pretty_print=True, 27 | ) 28 | # open(fname.replace('.xml', '-result.xml'), "wb").write(xml) 29 | -------------------------------------------------------------------------------- /examples/cert-info-pem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import pprint 5 | import binascii 6 | from cryptography.hazmat import backends 7 | from cryptography.hazmat.primitives import hashes, serialization 8 | from cryptography.hazmat.primitives.asymmetric import padding 9 | from cryptography.hazmat.primitives.serialization import pkcs12 10 | from asn1crypto import x509, pem 11 | 12 | 13 | def cert2asn(cert_bytes): 14 | if pem.detect(cert_bytes): 15 | _, _, cert_bytes = pem.unarmor(cert_bytes) 16 | return x509.Certificate.load(cert_bytes) 17 | 18 | def main(): 19 | if len(sys.argv) == 2: 20 | pemname = sys.argv[1] 21 | else: 22 | pemname = 'ca/demo2_ca.sub.crt.pem' 23 | data = open(pemname, 'rb').read() 24 | cert = cert2asn(data) 25 | pprint.pprint(cert.native) 26 | main() 27 | -------------------------------------------------------------------------------- /docs/endesive.pdf.rst: -------------------------------------------------------------------------------- 1 | endesive.pdf package 2 | ==================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | Submodules 11 | ---------- 12 | 13 | endesive.pdf.cms module 14 | ----------------------- 15 | 16 | .. automodule:: endesive.pdf.cms 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | 21 | endesive.pdf.pdf module 22 | ----------------------- 23 | 24 | .. automodule:: endesive.pdf.pdf 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | endesive.pdf.verify module 30 | -------------------------- 31 | 32 | .. automodule:: endesive.pdf.verify 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | 37 | Module contents 38 | --------------- 39 | 40 | .. automodule:: endesive.pdf 41 | :members: 42 | :undoc-members: 43 | :show-inheritance: 44 | -------------------------------------------------------------------------------- /endesive/plain/verify.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | from cryptography import x509 3 | 4 | from endesive import verifier 5 | 6 | def verify(datas:bytes, datau:bytes, certs:list[x509.Certificate]=None) -> tuple[bool, bool, bool]: 7 | """ 8 | Verifies signed bytes. 9 | 10 | Parameters: 11 | datas: Signed data as bytes. 12 | datau: Original data as bytes. 13 | certs: List of additional certificates used to verify signature (system independent). 14 | 15 | Returns: 16 | hashok, signatureok, certok 17 | 18 | hashok : bool 19 | True if the hash matches. 20 | signatureok : bool 21 | True if the signature is valid. 22 | certok : bool 23 | True if the certificate used for signing is trusted and valid. 24 | """ 25 | return verifier.verify(datas, datau, certs) 26 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/config/location.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Location 4 | ~~~~~~~~~~~~ 5 | Configuration for an annotation's location. 6 | 7 | :copyright: Copyright 2019 Autodesk, Inc. 8 | :license: MIT, see LICENSE for details. 9 | """ 10 | import attr 11 | 12 | from ..util.validation import Integer 13 | from ..util.validation import Number 14 | from ..util.validation import Points 15 | from ..util.validation import positive 16 | 17 | 18 | @attr.s 19 | class Location(object): 20 | page = Integer(validator=positive) 21 | points = Points(default=None) 22 | x1 = Number(default=None) 23 | y1 = Number(default=None) 24 | x2 = Number(default=None) 25 | y2 = Number(default=None) 26 | 27 | def copy(self): 28 | L = Location(page=self.page) 29 | for k, v in self.__dict__.items(): 30 | setattr(L, k, v) 31 | return L 32 | -------------------------------------------------------------------------------- /docs/endesive.rst: -------------------------------------------------------------------------------- 1 | endesive package 2 | ================ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | endesive.email 11 | endesive.pdf 12 | endesive.plain 13 | endesive.xades 14 | 15 | Submodules 16 | ---------- 17 | 18 | endesive.hsm module 19 | ------------------- 20 | 21 | .. automodule:: endesive.hsm 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | endesive.signer module 27 | ---------------------- 28 | 29 | .. automodule:: endesive.signer 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | endesive.verifier module 35 | ------------------------ 36 | 37 | .. automodule:: endesive.verifier 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | 42 | Module contents 43 | --------------- 44 | 45 | .. automodule:: endesive 46 | :members: 47 | :undoc-members: 48 | :show-inheritance: 49 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /examples/xml-xmlsigner-enveloping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from lxml import etree 4 | import signxml 5 | 6 | cert = open("ca/demo2_user1.crt.pem").read() 7 | key = open("ca/demo2_user1.key.pem").read() 8 | cert1 = open("ca/demo2_ca.sub.crt.pem").read() 9 | data = open('xml.xml', 'rb').read() 10 | 11 | root = etree.fromstring(data) 12 | 13 | signed_root = signxml.XMLSigner( 14 | method=signxml.methods.enveloping 15 | ).sign( 16 | root, 17 | key=key, 18 | cert=[cert, cert1], 19 | passphrase=b'1234' 20 | ) 21 | 22 | verified_data = signxml.XMLVerifier( 23 | ).verify( 24 | signed_root, 25 | ca_pem_file="ca/demo2_ca.root.crt.pem" 26 | ).signed_xml 27 | 28 | xml = etree.tostring( 29 | signed_root, 30 | encoding='UTF-8', 31 | xml_declaration=True, 32 | standalone=False, 33 | pretty_print=True 34 | ) 35 | open("xml-xmlsigner-enveloping.xml", "wb").write(xml) 36 | -------------------------------------------------------------------------------- /examples/smime-verify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import io 4 | from endesive import email 5 | 6 | 7 | def main(): 8 | trusted_cert_pems = (open('ca/root.pem', 'rb').read(),) 9 | 10 | for fname in ( 11 | 'smime-signed-attr.txt', 12 | 'smime-signed-attr-custom.txt', 13 | 'smime-signed-hsm.txt', 14 | 'smime-signed-noattr.txt', 15 | 'smime-signed-pss.txt', 16 | 'smime-ssl-pss-signed.txt', 17 | 'smime-ssl-signed-attr.txt', 18 | 'smime-ssl-signed-noattr.txt', 19 | ): 20 | print('*' * 20, fname) 21 | try: 22 | datae = io.open(fname, 'rt', encoding='utf-8').read() 23 | except: 24 | print('no such file') 25 | continue 26 | (hashok, signatureok, certok) = email.verify(datae, trusted_cert_pems) 27 | print('signature ok?', signatureok) 28 | print('hash ok?', hashok) 29 | print('cert ok?', certok) 30 | 31 | 32 | main() 33 | -------------------------------------------------------------------------------- /docs/endesive.email.rst: -------------------------------------------------------------------------------- 1 | endesive.email package 2 | ====================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | endesive.email.decrypt module 8 | ----------------------------- 9 | 10 | .. automodule:: endesive.email.decrypt 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | endesive.email.encrypt module 16 | ----------------------------- 17 | 18 | .. automodule:: endesive.email.encrypt 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | endesive.email.sign module 24 | -------------------------- 25 | 26 | .. automodule:: endesive.email.sign 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | endesive.email.verify module 32 | ---------------------------- 33 | 34 | .. automodule:: endesive.email.verify 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: endesive.email 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /examples/smime-decrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import io 4 | from cryptography.hazmat import backends 5 | from cryptography.hazmat.primitives.serialization import pkcs12 6 | from endesive import email 7 | 8 | 9 | def main(): 10 | with open('ca/demo2_user1.p12', 'rb') as fp: 11 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 12 | for fname in ( 13 | 'smime-ssl-encrypted.txt', 14 | 'smime-ssl-oaep-encrypted.txt', 15 | 'smime-encrypted.txt', 16 | 'smime-encrypted-oaep.txt', 17 | ): 18 | print('*' * 20, fname) 19 | try: 20 | datae = io.open(fname, 'rt', encoding='utf-8').read() 21 | except: 22 | print('no such file') 23 | continue 24 | datad = email.decrypt(datae, p12[0]) 25 | datad = datad.decode('utf-8') 26 | io.open(fname.replace('encrypted', 'decrypted'), 'wt', encoding='utf-8').write(datad) 27 | 28 | 29 | main() 30 | -------------------------------------------------------------------------------- /examples/plain-verify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from endesive import plain 4 | 5 | 6 | def main(): 7 | #trusted_cert_pems = (open('ca/demo2_ca.root.crt.pem', 'rb').read(),) 8 | trusted_cert_pems = (open('ca/root.pem', 'rb').read(),) 9 | datau = open('plain-unsigned.txt', 'rb').read() 10 | for fname in ( 11 | 'plain-ssl-signed-attr.txt', 12 | 'plain-ssl-signed-noattr.txt', 13 | 'plain-signed-attr.txt', 14 | 'plain-signed-noattr.txt', 15 | 'plain-signed-pss.txt', 16 | ): 17 | print('*' * 20, fname) 18 | try: 19 | datas = open(fname, 'rb').read() 20 | except FileNotFoundError: 21 | print("no such file", fname) 22 | continue 23 | (hashok, signatureok, certok) = plain.verify(datas, datau, trusted_cert_pems) 24 | print('signature ok?', signatureok) 25 | print('hash ok?', hashok) 26 | print('cert ok?', certok) 27 | 28 | 29 | main() 30 | -------------------------------------------------------------------------------- /endesive/plain/sign.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | from cryptography import x509 3 | from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes 4 | 5 | from endesive import signer 6 | 7 | 8 | def sign(datau:bytes, key: PrivateKeyTypes, cert: x509.Certificate, certs: list[x509.Certificate], hashalgo='sha1', attrs=True, pss=False) -> bytes: 9 | """ 10 | Sign data with private key without any encapsulation. 11 | 12 | Parameters: 13 | datau: Data to sign (bytes). 14 | key: Private key to sign with (PrivateKeyTypes). 15 | cert: Certificate to sign with (x509.Certificate). 16 | certs: List of additional certificates (list of x509.Certificate). 17 | hashalgo: Hash algorithm to use (str, default 'sha1'). 18 | attrs: Whether to include attributes (bool, default True). 19 | pss: Whether to use PSS padding (bool, default False). 20 | 21 | Returns: 22 | Signed data as bytes. 23 | """ 24 | return signer.sign(datau, key, cert, certs, hashalgo, attrs, pss=pss) 25 | -------------------------------------------------------------------------------- /examples/xml-xmlsigner-enveloped.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from lxml import etree 4 | import signxml 5 | 6 | cert = open("ca/demo2_user1.crt.pem").read() 7 | key = open("ca/demo2_user1.key.pem").read() 8 | cert1 = open("ca/demo2_ca.sub.crt.pem").read() 9 | data = open("xml.xml", "rb").read() 10 | 11 | root = etree.fromstring(data) 12 | 13 | signed_root = signxml.XMLSigner(method=signxml.methods.enveloped).sign( 14 | root, key=key, cert=[cert, cert1], passphrase=b"1234" 15 | ) 16 | 17 | verified_data = ( 18 | signxml.XMLVerifier().verify(signed_root, ca_pem_file="ca/demo2_ca.root.crt.pem").signed_xml 19 | ) 20 | 21 | xml = etree.tostring( 22 | signed_root, encoding="UTF-8", xml_declaration=True, standalone=False 23 | ) 24 | open("xml-xmlsigner-enveloped.xml", "wb").write(xml) 25 | 26 | xml = etree.tostring( 27 | signed_root, 28 | encoding="UTF-8", 29 | xml_declaration=True, 30 | standalone=False, 31 | pretty_print=True, 32 | ) 33 | open("xml-xmlsigner-enveloped1.xml", "wb").write(xml) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Grzegorz Makarewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/pdf-sign-fpdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import datetime 4 | from cryptography.hazmat import backends 5 | from cryptography.hazmat.primitives.serialization import pkcs12 6 | from endesive.pdf import pdf 7 | 8 | 9 | def main(): 10 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 11 | date = date.strftime('%Y%m%d%H%M%S+00\'00\'') 12 | dct = { 13 | 'sigflags': 3, 14 | 'contact': 'mak@trisoft.com.pl', 15 | 'location': 'Szczecin', 16 | 'signingdate': date, 17 | 'reason': 'Dokument podpisany cyfrowo', 18 | } 19 | with open('ca/demo2_user1.p12', 'rb') as fp: 20 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 21 | doc = pdf.FPDF() 22 | doc.pkcs11_setup(dct, 23 | p12[0], p12[1], p12[2], 24 | 'sha256' 25 | ) 26 | for i in range(2): 27 | doc.add_page() 28 | doc.set_font('helvetica', '', 13.0) 29 | doc.cell(w=75.0, h=22.0, align='C', txt='Hello, world page=%d.' % i, border=0, ln=0) 30 | doc.output('pdf-signed-fpdf.pdf', "F") 31 | 32 | 33 | main() 34 | -------------------------------------------------------------------------------- /LICENSE.pdf-annotate: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-present Autodesk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/fixtures/.gitignore: -------------------------------------------------------------------------------- 1 | cert-hsm-* 2 | demo2_* 3 | root.pem 4 | softhsm2/ 5 | softhsm2.conf 6 | pdf-signed-cms.pdf 7 | pdf-signed-cms-pss.pdf 8 | pdf-encrypted-signed.pdf 9 | pdf-signed-appearance.pdf 10 | pdf-signed-appearance-ec.pdf 11 | pdf-signed-appearance-manual.pdf 12 | pdf-signed-cms-aligned.pdf 13 | plain-signed-attr.txt 14 | plain-signed-noattr.txt 15 | plain-ssl-signed-attr.txt 16 | plain-ssl-signed-noattr.txt 17 | smime-encrypted.txt 18 | smime-signed-attr-custom.txt 19 | smime-signed-attr.txt 20 | smime-signed-noattr.txt 21 | smime-encrypted-aes128-cbc-False.txt 22 | smime-encrypted-aes128-cbc-True.txt 23 | smime-encrypted-aes128-ofb-False.txt 24 | smime-encrypted-aes128-ofb-True.txt 25 | smime-encrypted-aes192-cbc-False.txt 26 | smime-encrypted-aes192-cbc-True.txt 27 | smime-encrypted-aes192-ofb-False.txt 28 | smime-encrypted-aes192-ofb-True.txt 29 | smime-encrypted-aes256-cbc-False.txt 30 | smime-encrypted-aes256-cbc-True.txt 31 | smime-encrypted-aes256-ofb-False.txt 32 | smime-encrypted-aes256-ofb-True.txt 33 | smime-ssl-encrypted-cms-None.txt 34 | smime-ssl-encrypted-cms-oaep.txt 35 | smime-ssl-encrypted-smime-aes256.txt 36 | smime-signed-attr-pss.txt 37 | smime-signed-hsm-ssh.txt 38 | -------------------------------------------------------------------------------- /examples/smime-sign-attr-custom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from cryptography.hazmat import backends 4 | from cryptography.hazmat.primitives.serialization import pkcs12 5 | from endesive import email 6 | 7 | import hashlib 8 | from asn1crypto import cms, algos, core, pem, x509 9 | 10 | def main(): 11 | with open('ca/demo2_user1.p12', 'rb') as fp: 12 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 13 | datau = open('smime-unsigned.txt', 'rb').read() 14 | 15 | datau1 = datau.replace(b'\n', b'\r\n') 16 | hashalgo = 'sha256' 17 | signed_value = getattr(hashlib, hashalgo)(datau1).digest() 18 | attrs = [ 19 | cms.CMSAttribute({ 20 | 'type': cms.CMSAttributeType('content_type'), 21 | 'values': ('data',), 22 | }), 23 | cms.CMSAttribute({ 24 | 'type': cms.CMSAttributeType('message_digest'), 25 | 'values': (signed_value,), 26 | }), 27 | ] 28 | 29 | datas = email.sign(datau, 30 | p12[0], p12[1], p12[2], 31 | 'sha256', 32 | attrs=attrs 33 | ) 34 | open('smime-signed-attr-custom.txt', 'wb').write(datas) 35 | 36 | 37 | main() 38 | -------------------------------------------------------------------------------- /examples/ca/demo2_ca.root.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDLTCCAhWgAwIBAgIUHeQXwdDU4jyXtdItkEjDOw/SigAwDQYJKoZIhvcNAQEL 3 | BQAwHTEbMBkGA1UEAwwSQUEgVHJpU29mdCBSb290IENBMCAXDTI1MDYxMTE4Mjgw 4 | MloYDzIwNjUwNjAxMTgyODAyWjAdMRswGQYDVQQDDBJBQSBUcmlTb2Z0IFJvb3Qg 5 | Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCGHskGb4Gd364QhbS6 6 | i2NmHbJf4N5LhDJPwRjDACuRqRu42fEB+MwKvAIYoS2wVihYubf/dRZFc0/4yyCH 7 | 7I1Mkh1YoQRjl3q51pKWjUjm5Ua611NDLHvkDU8ecQWj2qjHcJtV39ay3L/TIyvS 8 | tesIR+o2oOkfxzaLjkhrH08DOy5L3gvETexV7GBbmSQTaI9jvNuD9oKZs6ba1S5O 9 | 65pPEC/u3/udZgRBKd+lB/qlLk7HNuN0trwEfZLvdBC4pS9Fc0DbUcHnsNBwWFc9 10 | VjrzzJDYHdWmZtYGg5rc7efx5+zVw26wm58caJv5ihi0An4J/I8i5I4TKoLMgcJP 11 | 2r7VAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUPkWmCmbq 12 | vZJeJaiLKy8j/la8iHEwHQYDVR0OBBYEFD5Fpgpm6r2SXiWoiysvI/5WvIhxMA4G 13 | A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAPc3cf1CHKSaF4BDM8UHT 14 | 4B5VMdj7uZSxsQ+IerrOi6QfMIUuesVc/h9oN9eBLoTCCQsFB7nrizwmyd2xIK9d 15 | jOuPQZexu9VhBIeJE8Fh86gG0U6IQxXw9NXW10yaW9w5RAYQqH3w+VPsaPDXnceX 16 | b0yjM1vtmV9WrMNoXWPil7vYuea0HAar80IyUKwrzEOZa8zqDz1HElC0rukVh0Yl 17 | 5PHkVptl11d81ukyKeXGP6PFt1JI31vgAEZHdykz8w7SjAu0g+QrM2LCZV915wLu 18 | OAS3ptxRmdNymk1zYHEyPt7CRdgUV1NWhE1N0RQMuf1CnXRPWZ6+Ls83xVzoO1i7 19 | WA== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /examples/pdf-dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | 5 | 6 | def show(fname): 7 | print('*' * 20, fname) 8 | data = open(fname, 'rb').read() 9 | s = data.find(b'xref') 10 | while s > 0: 11 | e = data.find(b'trailer', s) - 1 12 | offsets = data[s:e].split(b'\n') 13 | print(offsets) 14 | if 1: 15 | for offset in offsets[2:]: 16 | offset = offset.split() 17 | if len(offset) != 3: 18 | continue 19 | offset = int(offset[0], 10) 20 | sdata = data[offset:offset + 32].split(b'\n')[0] 21 | print(offset, '->', sdata) 22 | s = data.find(b'%%EOF', e) 23 | print('%%EOF at', s) 24 | s = data.find(b'xref', s) 25 | 26 | s = data.find(b'/ByteRange') 27 | if s > 0: 28 | start = data.find(b'[', s) + 1 29 | end = data.find(b']', s) 30 | byterange = [int(i, 10) for i in data[start:end].split()] 31 | print('/ByteRange', ':', s, start, end, ':', byterange) 32 | print('/Contents', ':', chr(data[byterange[1]]), '...', chr(data[byterange[2] - 1])) 33 | 34 | 35 | def main(): 36 | show(sys.argv[1]) 37 | 38 | 39 | main() 40 | -------------------------------------------------------------------------------- /examples/pdfviewer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import wx 3 | import wx.lib.sized_controls as sc 4 | import sys 5 | from wx.lib.pdfviewer import pdfViewer, pdfButtonPanel 6 | 7 | class PDFViewer(sc.SizedFrame): 8 | def __init__(self, parent, **kwds): 9 | super(PDFViewer, self).__init__(parent, **kwds) 10 | 11 | paneCont = self.GetContentsPane() 12 | self.buttonpanel = pdfButtonPanel(paneCont, wx.NewId(), 13 | wx.DefaultPosition, wx.DefaultSize, 0) 14 | self.buttonpanel.SetSizerProps(expand=True) 15 | self.viewer = pdfViewer(paneCont, wx.NewId(), wx.DefaultPosition, 16 | wx.DefaultSize, 17 | wx.HSCROLL|wx.VSCROLL|wx.SUNKEN_BORDER) 18 | 19 | self.viewer.SetSizerProps(expand=True, proportion=1) 20 | 21 | # introduce buttonpanel and viewer to each other 22 | self.buttonpanel.viewer = self.viewer 23 | self.viewer.buttonpanel = self.buttonpanel 24 | 25 | 26 | if __name__ == '__main__': 27 | import wx.lib.mixins.inspection as WIT 28 | app = WIT.InspectableApp(redirect=False) 29 | fname = sys.argv[1] 30 | pdfV = PDFViewer(None, size=(800, 600)) 31 | pdfV.viewer.LoadFile(fname) 32 | pdfV.Show() 33 | 34 | app.MainLoop() -------------------------------------------------------------------------------- /examples/test-certificate-googleHSM.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDZDCCAkygAwIBAgIUZytKw5S15LEbmWqF3dluaI/5pR4wDQYJKoZIhvcNAQEL 3 | BQAwajEQMA4GA1UEBhMHRW5nbGFuZDEXMBUGA1UECAwOR3JlYXRlciBMb25kb24x 4 | DzANBgNVBAcMBkxvbmRvbjEVMBMGA1UECgwMR29vZ2xlSFNNIENBMRUwEwYDVQQD 5 | DAxHb29nbGVIU00gQ0EwHhcNMjAwOTA2MTgwNDU3WhcNMjEwOTA3MTgwNDU3WjBq 6 | MRAwDgYDVQQGEwdFbmdsYW5kMRcwFQYDVQQIDA5HcmVhdGVyIExvbmRvbjEPMA0G 7 | A1UEBwwGTG9uZG9uMRUwEwYDVQQKDAxHb29nbGVIU00gQ0ExFTATBgNVBAMMDEdv 8 | b2dsZUhTTSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJG8KDay 9 | zfTER4ldJYEddVam5k76GaGFGKIvG/r63+sIrXrMtoEdzAU8ZSpLGusE9CF5K7el 10 | tIt21JJwyFWEcD3w4wxtPJK8T0tfarfWOx6AWUkYhmGuO5nK8rI/lrbK3vvJBN1S 11 | ju1w6JyAY0ygHrgXMLbosUrDtSovMdsyHHiHmWOmxvPzZxXJrp4a92wN2E1cvp+1 12 | oFff58OSGPNIJsR21xvAtdDNgiXd52Ltoc2MTObj258fvXRHXuSlkZiCkCDbgOTU 13 | ZoSsb3ysH7weUIGO24ZJ0rGz069ACUzumo82PeaBvFWg8LhVURmOpewRBv6ONh4+ 14 | Wv3PeSFtx48L+ikCAwEAAaMCMAAwDQYJKoZIhvcNAQELBQADggEBAGQ0Pem3z2fg 15 | wsNu9b45aAb/8zAVBSlHmLkdA1A8dUfCmm2kHR5yWlC/dTzt5zdfbNZq8T5OfJfa 16 | tiLiCza/3xs979H6+nVKUKCTJIbfFkBDKZmBjkNJbB4R5yxVPg1HjlSYWltEo4EZ 17 | u577G1ejxkTEZFQALPmar4PBggZEqLqJMxjxgNEwS3Z2DildFPF7JF2m2Jj3zq7y 18 | nJhI8TpimTzV+rChZYPasWqV/Dcv6aNrZcCcgb9pJsR8aCvtrEdo96LNlGZUVBuW 19 | wZA/QkgO/0LgftXXYLzPWzDFofLUCpNnppMMgpi0ybgzS/bi+1zdvgJZEVVUwKOe 20 | frp5mIvq49k= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /examples/cert-info-p12.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import pprint 5 | import binascii 6 | from cryptography.hazmat import backends 7 | from cryptography.hazmat.primitives import hashes, serialization 8 | from cryptography.hazmat.primitives.asymmetric import padding 9 | from cryptography.hazmat.primitives.serialization import pkcs12 10 | from asn1crypto import x509, pem 11 | 12 | 13 | def cert2asn(cert): 14 | cert_bytes = cert.public_bytes(serialization.Encoding.PEM) 15 | if pem.detect(cert_bytes): 16 | _, _, cert_bytes = pem.unarmor(cert_bytes) 17 | return x509.Certificate.load(cert_bytes) 18 | 19 | def main(): 20 | if len(sys.argv) == 3: 21 | p12name = sys.argv[1] 22 | p12pass = sys.argv[2] 23 | else: 24 | p12name = 'ca/demo2_user1.p12' 25 | p12pass = '1234' 26 | print(len(sys.argv), p12name, p12pass) 27 | with open(p12name, 'rb') as fp: 28 | p12pk, p12pc, p12oc = pkcs12.load_key_and_certificates(fp.read(), p12pass.encode(), backends.default_backend()) 29 | signature = p12pk.sign( 30 | b"message", 31 | padding.PKCS1v15(), 32 | hashes.SHA1() 33 | ) 34 | cert = cert2asn(p12pc) 35 | print('issuer', cert.issuer.native) 36 | print('subject', cert.subject.native) 37 | pprint.pprint(cert.native) 38 | main() 39 | -------------------------------------------------------------------------------- /examples/pdf-timestamp-cms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | dct = { 18 | "aligned": 0, 19 | "sigflags": 3, 20 | "sigflagsft": 132, 21 | "sigpage": 0, 22 | "sigfield": "Signature1", 23 | "auto_sigfield": True, 24 | "password": "1234", 25 | "signingdate": "2025-06-11", 26 | } 27 | fname = "pdf.pdf" 28 | if len(sys.argv) > 1: 29 | fname = sys.argv[1] 30 | datau = open(fname, "rb").read() 31 | datas = cms.timestamp( 32 | datau, # PDF data 33 | dct, # config 34 | "sha256", # hash 35 | 'https://freetsa.org/tsr' # Timestamp server URL 36 | # { # Timestamp server credentials 37 | # 'username': 'user', 38 | # 'password': 'hunter2' 39 | # }, 40 | # {}, Timestamp server options 41 | ) 42 | fname = fname.replace(".pdf", "-timestamped-cms.pdf") 43 | with open(fname, "wb") as fp: 44 | fp.write(datau) 45 | fp.write(datas) 46 | 47 | 48 | main() 49 | -------------------------------------------------------------------------------- /examples/plain-openssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # http://qistoph.blogspot.com/2012/01/manual-verify-pkcs7-signed-data-with.html 3 | # https://security.stackexchange.com/questions/176329/verify-s-mime-signature-with-no-certificate-included 4 | 5 | sign1() { 6 | openssl smime -sign \ 7 | -md sha256 \ 8 | -binary \ 9 | -CAfile ca/demo2_ca.sub.crt.pem \ 10 | -in $1 -out $2 -outform der \ 11 | -inkey ca/demo2_user1.key.pem -passin pass:1234 \ 12 | -signer ca/demo2_user1.crt.pem 13 | } 14 | 15 | sign2() { 16 | cat ca/demo2_user1.crt.pem ca/demo2_ca.sub.crt.pem >x-cert.tmp 17 | openssl smime -sign \ 18 | -md sha256 \ 19 | -binary -noattr \ 20 | -CAfile ca/demo2_ca.root.crt.pem \ 21 | -in $1 -out $2 -outform der \ 22 | -inkey ca/demo2_user1.key.pem -passin pass:1234 \ 23 | -signer x-cert.tmp 24 | rm x-cert.tmp 25 | } 26 | 27 | verify() { 28 | openssl smime -verify \ 29 | -CAfile ca/root.pem \ 30 | -content $1 \ 31 | -in $2 -inform der 32 | } 33 | 34 | if [ -z "$1" ]; then 35 | echo "************************** attr" 36 | sign1 plain-unsigned.txt plain-ssl-signed-attr.txt 37 | verify plain-unsigned.txt plain-ssl-signed-attr.txt 38 | echo "************************** noattr" 39 | sign2 plain-unsigned.txt plain-ssl-signed-noattr.txt 40 | verify plain-unsigned.txt plain-ssl-signed-noattr.txt 41 | else 42 | echo "************************** verify" 43 | verify plain-unsigned.txt $1 44 | fi 45 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.insert(0, os.path.abspath('..')) 4 | # Configuration file for the Sphinx documentation builder. 5 | # 6 | # For the full list of built-in configuration values, see the documentation: 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 8 | 9 | # -- Project information ----------------------------------------------------- 10 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 11 | 12 | project = 'endesive' 13 | copyright = '2025, Grzegorz Makarewicz' 14 | author = 'Grzegorz Makarewicz' 15 | #release = '1.0.0' 16 | 17 | # -- General configuration --------------------------------------------------- 18 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 19 | 20 | extensions = [ 21 | 'sphinx.ext.autodoc', 22 | 'sphinx.ext.viewcode', 23 | 'sphinx.ext.napoleon', 24 | ] 25 | 26 | templates_path = ['_templates'] 27 | exclude_patterns = [ 28 | '_build', 29 | 'Thumbs.db', 30 | '.DS_Store', 31 | 'examples', 32 | 'tests', 33 | 'endesive/pdf/fpdf*', 34 | 'endesive/pdf/PyPDF2*', 35 | 'endesive/pdf/PyPDF2_annotate*', 36 | ] 37 | 38 | 39 | 40 | # -- Options for HTML output ------------------------------------------------- 41 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 42 | 43 | html_theme = 'sphinx_rtd_theme' 44 | html_static_path = ['_static'] 45 | -------------------------------------------------------------------------------- /examples/ca/demo2_ca.sub.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDzzCCAregAwIBAgIUZApuK7Hcoiz740Eknrz1eN5zohcwDQYJKoZIhvcNAQEL 3 | BQAwHTEbMBkGA1UEAwwSQUEgVHJpU29mdCBSb290IENBMB4XDTI1MDYxMTE4Mjgw 4 | MloXDTM1MDYwOTE4MjgwMlowJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1l 5 | ZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHZyrEWyxN 6 | iwVC5afAaVU4hlDEBTeqFsu0YPkFRRNFPVhX+CrLMPlKLy97Zq86Viw9Tu2ob8QN 7 | EUeYIDpjcYjZqJZj2fdaoCMam/WwZlonQqvyEzqRshe4kRACUdfDdfamCK6RFini 8 | Yxfq34B+27yI3aFwIY1/3oQKm0uP92fLpIzL5w3HT94CZEdGVDuALPs9D/kF+PG1 9 | Si+S8/m3rZx3PfCAQAhvh2V1pG3LqFf/UiFXWoLWLex3w4APPwRbuFUYjtarLr+5 10 | GhUfmOf16rH5Ic6tbdlMFDaet/VBasbmCc+OBjL0R1GEErnB/8Nr5IXTYV55cZDJ 11 | Z/3b0M9wh1AfAgMBAAGjgf4wgfswEgYDVR0TAQH/BAgwBgEB/wIBADAtBgNVHR8E 12 | JjAkMCKgIKAehhxodHRwOi8vY2EudHJpc29mdC5jb20ucGwvY3JsMGYGCCsGAQUF 13 | BwEBBFowWDArBggrBgEFBQcwAoYfaHR0cDovL2NhLnRyaXNvZnQuY29tLnBsL2Nh 14 | Y2VydDApBggrBgEFBQcwAYYdaHR0cDovL2NhLnRyaXNvZnQuY29tLnBsL29jc3Aw 15 | HwYDVR0jBBgwFoAUPkWmCmbqvZJeJaiLKy8j/la8iHEwHQYDVR0OBBYEFLuhhALL 16 | AEAUz1v1QQzM00vhi4lIMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC 17 | AQEAPjIEUaksu9VvPmQZ8MSTLBAzRWg+un6Ww9GZZ1gBfBoENyxz6+va5D90N/Jg 18 | qJP58WJUtfdTLiHDTRb2z5h4cl4YHCf4HmgMgrzLhe7yjAjtpRokfzQlUFmcQewh 19 | KJgUH4eOw1g04etMCQbMx0wDF3J35hsKwiTxIEwjhYsqCmCXs9LKtJj/RFSTOp4r 20 | kSzAfYYTMYWW/nRtVtjq4BgMR29f8BiM1q7/GrBlppc4fdadwnOOh8M8ZM7NUEhR 21 | 6Xk69Ut7P4VvbyYuv+lkXpWJ2quDpXu5IF0GwBGfWkXnFps9k5FFTAzIBOXPab4x 22 | Q88Jg+YGQMFmfnVvfKh8ySi2WA== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/config/constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Constants 4 | ~~~~~~~~~ 5 | 6 | :copyright: Copyright 2019 Autodesk, Inc. 7 | :license: MIT, see LICENSE for details. 8 | """ 9 | TEXT_ALIGN_LEFT = 'left' 10 | TEXT_ALIGN_CENTER = 'center' 11 | TEXT_ALIGN_RIGHT = 'right' 12 | ALLOWED_ALIGNS = ( 13 | TEXT_ALIGN_LEFT, 14 | TEXT_ALIGN_RIGHT, 15 | TEXT_ALIGN_CENTER, 16 | ) 17 | 18 | TEXT_BASELINE_TOP = 'top' 19 | TEXT_BASELINE_MIDDLE = 'middle' 20 | TEXT_BASELINE_BOTTOM = 'bottom' 21 | ALLOWED_BASELINES = ( 22 | TEXT_BASELINE_TOP, 23 | TEXT_BASELINE_MIDDLE, 24 | TEXT_BASELINE_BOTTOM, 25 | ) 26 | 27 | DEFAULT_CONTENT = '' 28 | DEFAULT_FONT_SIZE = 12 29 | DEFAULT_LINE_SPACING = 1.2 30 | 31 | DEFAULT_STROKE_WIDTH = 1 32 | DEFAULT_BORDER_STYLE = 'S' 33 | 34 | LINE_CAP_BUTT = 0 35 | LINE_CAP_ROUND = 1 36 | LINE_CAP_SQUARE = 2 37 | ALLOWED_LINE_CAPS = ( 38 | LINE_CAP_BUTT, 39 | LINE_CAP_ROUND, 40 | LINE_CAP_SQUARE, 41 | ) 42 | 43 | LINE_JOIN_MITER = 0 44 | LINE_JOIN_ROUND = 1 45 | LINE_JOIN_BEVEL = 2 46 | ALLOWED_LINE_JOINS = ( 47 | LINE_JOIN_MITER, 48 | LINE_JOIN_ROUND, 49 | LINE_JOIN_BEVEL, 50 | ) 51 | 52 | BLACK = (0, 0, 0) 53 | TRANSPARENT = tuple() 54 | 55 | GRAPHICS_STATE_NAME = 'PdfAnnotatorGS' 56 | DEFAULT_BASE_FONT = 'Helvetica' 57 | PDF_ANNOTATOR_FONT = 'PDFANNOTATORFONT1' 58 | 59 | CMYK_MODE = 'CMYK' 60 | RGB_MODE = 'RGB' 61 | RGBA_MODE = 'RGBA' 62 | PALETTE_MODE = 'P' 63 | GRAYSCALE_MODE = 'L' 64 | GRAYSCALE_ALPHA_MODE = 'LA' 65 | SINGLE_CHANNEL_MODE = '1' 66 | -------------------------------------------------------------------------------- /examples/pdf-make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | from optparse import OptionParser 5 | from endesive.pdf import fpdf 6 | 7 | parser = OptionParser() 8 | parser.add_option("-f", "--file", dest="filename", default="pdf.pdf", 9 | help="write document to FILE", metavar="FILE") 10 | parser.add_option("-l", "--link", 11 | action="store_true", dest="link", default=False, 12 | help="add link on page 1 to page 2") 13 | parser.add_option("-t", "--ttf", dest="pdf_font", default="", 14 | help="set ttf font for document") 15 | parser.add_option("-v", "--pdf-version", dest="pdf_version", default="1.3", 16 | help="set pdf vesion of generated document") 17 | 18 | (options, args) = parser.parse_args() 19 | 20 | doc = fpdf.FPDF() 21 | doc.pdf_version = options.pdf_version 22 | doc.set_compression(0) 23 | font = 'helvetica' 24 | if options.pdf_font: 25 | font = options.pdf_font.replace('\\', '/').split('/')[-1].split('.')[0] 26 | doc.add_font(font, '', options.pdf_font, True) 27 | 28 | for i in range(2): 29 | doc.add_page() 30 | doc.set_font(font, '', 13.0) 31 | link = None 32 | if options.link and i == 0: 33 | link = doc.add_link() 34 | doc.set_link(link, page=2) 35 | doc.cell(w=75.0, h=22.0, align='C', txt='Hello, world page=%d.' % i, border=0, ln=2, link=link) 36 | if font != 'helvetica': 37 | doc.cell(w=75.0, h=22.0, align='C', txt='ąćęłńóśżź', border=0, ln=2) 38 | doc.output(options.filename, "F") 39 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-pil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | from PIL import Image 8 | from endesive import pdf 9 | 10 | #import logging 11 | #logging.basicConfig(level=logging.DEBUG) 12 | 13 | def main(): 14 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 15 | date = date.strftime('%Y%m%d%H%M%S+00\'00\'') 16 | img = Image.open('signature_test.png') 17 | dct = { 18 | 'sigflags': 3, 19 | # 'sigpage': 0, 20 | 'sigbutton': True, 21 | 'signature_img': img, 22 | 'contact': 'mak@trisoft.com.pl', 23 | 'location': 'Szczecin', 24 | 'signingdate': date.encode(), 25 | 'reason': 'Dokument podpisany cyfrowo', 26 | 'signature': 'Dokument podpisany cyfrowo', 27 | 'signaturebox': (470, 0, 570, 100), 28 | } 29 | with open('ca/demo2_user1.p12', 'rb') as fp: 30 | p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) 31 | fname = 'pdf.pdf' 32 | if len (sys.argv) > 1: 33 | fname = sys.argv[1] 34 | datau = open(fname, 'rb').read() 35 | datas = pdf.cms.sign(datau, dct, 36 | p12[0], 37 | p12[1], 38 | p12[2], 39 | 'sha256' 40 | ) 41 | fname = fname.replace('.pdf', '-signed-cms-pil.pdf') 42 | with open(fname, 'wb') as fp: 43 | fp.write(datau) 44 | fp.write(datas) 45 | 46 | 47 | main() 48 | -------------------------------------------------------------------------------- /endesive/email/verify.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | from email import message_from_string 3 | 4 | from cryptography import x509 5 | 6 | from endesive import verifier 7 | 8 | 9 | def verify(data:bytes, certs:list[x509.Certificate]=None) -> tuple[bool, bool, bool]: 10 | """ 11 | Verifiy S/MIME signed email. 12 | 13 | :param data: Email data as bytes. 14 | :param certs: List of additional certificates used to verify signature (system independent). 15 | :return: 16 | hashok, signatureok, certok 17 | 18 | hashok: bool 19 | True if the hash matches. 20 | signatureok: bool 21 | True if the signature is valid. 22 | certok: bool 23 | True if the certificate used for signing is trusted and valid. 24 | """ 25 | msg = message_from_string(data) 26 | sig = None 27 | plain = None 28 | for part in msg.walk(): 29 | ct = part.get_content_type() 30 | # multipart/* are just containers 31 | if ct.split('/')[0] == 'multipart': 32 | continue 33 | if ct == 'application/x-pkcs7-signature': 34 | sig = part.get_payload(decode=True) 35 | elif ct == 'application/pkcs7-signature': 36 | sig = part.get_payload(decode=True) 37 | elif ct == 'text/plain': 38 | plain = part.get_payload(decode=False) 39 | if sig is None: 40 | raise ValueError('not signed email') 41 | 42 | plain = plain.encode('utf-8') 43 | plain = plain.replace(b'\n', b'\r\n') 44 | 45 | return verifier.verify(sig, plain, certs) 46 | -------------------------------------------------------------------------------- /examples/ca/demo2_user1.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEQjCCAyqgAwIBAgIUETiZ02Rox9YLIwNrJGLQIXXD2cowDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUw 4 | NzEzMDkzMzQ4WhcNMjYwNzEzMDkzMzQ4WjA+MRcwFQYDVQQDDA50cmlzb2Z0LmNv 5 | bS5wbDEjMCEGCSqGSIb3DQEJARYUZGVtbzFAdHJpc29mdC5jb20ucGwwggEiMA0G 6 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDT7I5p8UUbR35o/fIU7GaXkz6+CX+m 7 | s3h9xPZy1IUgGib7RRzrw5wwL25H0Ib7EVupeBRSfiHEEsC61pXwUJG/soYy8CMN 8 | f7m1/wyb8Y+qnuBVe7rrZQ7/T91Kuk3lfCknDsFCEKJx3l01jSlEWdrRybRSfaxk 9 | R4q05OorLrkvib9YD/w2isxVBf8OJ/B2Ie8IyN7zwy3lWjPPm1Oc8GJBqPoJx2fe 10 | s+G18ifJToB+mIrtyb1HKOdBG2QKzQQSVBwxaeNEEMvbaErj0AkgOqzEPje/8aPV 11 | qtKSXWg4zBg4h1LjEHHSMxC0jVerMFBJHRU0vmOaBm2DMH1IqfBRi20TAgMBAAGj 12 | ggFPMIIBSzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFLuhhALLAEAUz1v1QQzM 13 | 00vhi4lIMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9jYS50cmlzb2Z0LmNvbS5w 14 | bC9jcmwwZgYIKwYBBQUHAQEEWjBYMCsGCCsGAQUFBzAChh9odHRwOi8vY2EudHJp 15 | c29mdC5jb20ucGwvY2FjZXJ0MCkGCCsGAQUFBzABhh1odHRwOi8vY2EudHJpc29m 16 | dC5jb20ucGwvb2NzcDAfBgNVHREEGDAWgRRkZW1vMUB0cmlzb2Z0LmNvbS5wbDAz 17 | BgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCCsGAQUF 18 | BwMkMB0GA1UdDgQWBBSq3OLpKtQLoUloGV0yHx9I1S/3jjAOBgNVHQ8BAf8EBAMC 19 | A/gwDQYJKoZIhvcNAQELBQADggEBAIIiBK1zA6rYl7gXrqeppjNW0y1gm0tOyVjR 20 | TmwY8tqnaj5xRaMp4SJTgM1Zzw20HkQk4PzwVZl1qRFu/+6ceplengytmhv8n5il 21 | ZFfPtbgopWeyYNr4QHu6QZEJvlSZr4gB925Fm3FxbJ6Bk2ygKmdjjub9dJFiQPeB 22 | ATFM8hAZpnYxvse32t87kHyFFHXCRicbvO3jO/XPnbZi+4G+cyuAbuBR0Hjqs06+ 23 | qG8ibEs7bctDznv10D3gJhvMlDwm7ipXQWSbqw+vL7OIeKRICCwDzv68NLd9Jw5W 24 | s+T/MYxwnpF7gDPXMqWj0QjLfJEROMmi4uZI4u/2Q8KPEpg49ys= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /examples/ca/demo2_user2.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEQjCCAyqgAwIBAgIUMooMynJ146HDsH1AQ+ij62oGUq4wDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUw 4 | NzEzMDkzMzQ5WhcNMjYwNzEzMDkzMzQ5WjA+MRcwFQYDVQQDDA50cmlzb2Z0LmNv 5 | bS5wbDEjMCEGCSqGSIb3DQEJARYUZGVtbzJAdHJpc29mdC5jb20ucGwwggEiMA0G 6 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrzTveSY2QKTuxVmJn4fYwrzZ0Sv9i 7 | 34VN6zrn+ac6cGmhfKaNeBMUnLrtRsZ1sUhN+sNOTgdupWeY/tlt78FJXY/uyc9y 8 | V4QBDRpxCLvH6rcjexbwTf3geAO1AA8nmRR/aweXggKk84sFg12QfV9MxgVNAN5x 9 | sBTwNPq/EEuD7ar+Aztn8dcg2/GkZZ6Ab0tu7jXQEwy25lXWKKZW7avbsoK7aDpB 10 | +mAIWN21whXMbTqIgsjx7aQOOm05A2g5UzWN/eCVvVlDcIFhBxGlHeiF2r9slkZS 11 | oC08neaqKlTLgyV8l8scHnzryI/wVP0pvg3qNqxr532lorOi/mGdcHudAgMBAAGj 12 | ggFPMIIBSzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFLuhhALLAEAUz1v1QQzM 13 | 00vhi4lIMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9jYS50cmlzb2Z0LmNvbS5w 14 | bC9jcmwwZgYIKwYBBQUHAQEEWjBYMCsGCCsGAQUFBzAChh9odHRwOi8vY2EudHJp 15 | c29mdC5jb20ucGwvY2FjZXJ0MCkGCCsGAQUFBzABhh1odHRwOi8vY2EudHJpc29m 16 | dC5jb20ucGwvb2NzcDAfBgNVHREEGDAWgRRkZW1vMkB0cmlzb2Z0LmNvbS5wbDAz 17 | BgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCCsGAQUF 18 | BwMkMB0GA1UdDgQWBBSvX/NWnQ5db3+aFPugiON/OZB87jAOBgNVHQ8BAf8EBAMC 19 | A/gwDQYJKoZIhvcNAQELBQADggEBAEtk7sXGYLP/PruWo1tmGKuY3bSorD/0qGmt 20 | 5nXqcrj8lc+UkS2OV0OGjLA7G7IlJPWnePkgACDC5MxZWseWIEQrH2OQVWtLwkoJ 21 | +3tYfLeyMhd0Me/jmgDvE6lyXItzo8I77efSSfhS/etOFAldvBPV7qBTKnx7PV7p 22 | xbiy5w/1CwGGDGG1UXBBuh+F/sKwNkNeDp3v5iTWkgtPUDkPvSwDFUOJyl9CIXyc 23 | ejWhLTueudO6TDav6kS41rDFPlVdMYrKPZoAXSQ3tY4WapmIyJq2VVVoiQBdWFTe 24 | GrarSkIhLYyJEIHVc4Q9u4Lpb6WxqnEo8k7NUvZovDw6MWM8YEg= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /examples/ca/demo2_user3.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEQjCCAyqgAwIBAgIUK3QbxJq1Fxh92yf7qlq0NU4isXgwDQYJKoZIhvcNAQEL 3 | BQAwJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUw 4 | NzEzMDkzMzQ5WhcNMjYwNzEzMDkzMzQ5WjA+MRcwFQYDVQQDDA50cmlzb2Z0LmNv 5 | bS5wbDEjMCEGCSqGSIb3DQEJARYUZGVtbzNAdHJpc29mdC5jb20ucGwwggEiMA0G 6 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnTcm7NaS12tO9psWoMRRPxOUjDm38 7 | xsmSj0K7GlnfSLG/2KqItqp0HuZaTSDNKspx7yhfTL40hW2cDnT4tAYT3G7SG9z+ 8 | n3/pu1wylu1LJeC7pdFJgays3M+K9tQ9I6wY7+puwjiHrYu4SZqntNMruXPAhXy9 9 | Ty2LhSO+3oMB+AtK82UXvFcskw9I1IJu9VMvOnvJr61GQXxDOkGpbGmmNQ8XpPwm 10 | P87mOLyi0cUqN3eaEmCRTu0KmazeTVmcTw4gYqWr+Usqit5XjXJKa/Ms1KTGVKsk 11 | OIEVo3IK3hZVVCl79msExR2AnAp53oBzAOqPJKsywTNPgHdNon0CQCe7AgMBAAGj 12 | ggFPMIIBSzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFLuhhALLAEAUz1v1QQzM 13 | 00vhi4lIMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9jYS50cmlzb2Z0LmNvbS5w 14 | bC9jcmwwZgYIKwYBBQUHAQEEWjBYMCsGCCsGAQUFBzAChh9odHRwOi8vY2EudHJp 15 | c29mdC5jb20ucGwvY2FjZXJ0MCkGCCsGAQUFBzABhh1odHRwOi8vY2EudHJpc29m 16 | dC5jb20ucGwvb2NzcDAfBgNVHREEGDAWgRRkZW1vM0B0cmlzb2Z0LmNvbS5wbDAz 17 | BgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCCsGAQUF 18 | BwMkMB0GA1UdDgQWBBRYSlcpYIHkZ8xdetJFOMBv2dNGrDAOBgNVHQ8BAf8EBAMC 19 | A/gwDQYJKoZIhvcNAQELBQADggEBAGezAAq/XgUlOioryjG2t4rAno/WxX+Y13v3 20 | tOAgsSYcUJ3H+lttteA9YWeUSul37rUzjNQzub4bg1RmzkR7PhMIPjDDkbaZyXn3 21 | pTRtKAXIeWjTIRvqIDkHYjrlT9bC2oYTwlxXQ4FszumkdJBFEyr8JFs25i2SzRnK 22 | 0sW4hJTYZcIvv3015rW8GLDBLlpXjfR/1jiD662hCLc3ibFO0gjeTs4K1/TNGdzq 23 | ulH2NRqmD2rrD2hFP4uVsryOsTeSLoH/0RH+56yQhpuenLXnQzleKafMjvxuw90q 24 | 7ge+0lkykWXas/8wISMTgmOSbDl/49f+fTYKcBkKxjoBsK6XENc= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/util/font_metrics.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Font Metrics Utils 4 | ~~~~~~~~~~ 5 | 6 | :copyright: Copyright 2019 Autodesk, Inc. 7 | :license: MIT, see LICENSE for details. 8 | """ 9 | import attr 10 | 11 | from .validation import Number, List, Dict 12 | 13 | 14 | @attr.s 15 | class FontMetrics: 16 | """ 17 | Class to hold our font metric calculations. 18 | """ 19 | italicAngle = Number(default=0) 20 | usWeightClass = Number(default=500) 21 | isFixedPitch = Number(default=0) 22 | 23 | unitsPerEm = Number(default=1000) 24 | scale = Number(default=float(1)) 25 | bbox = List(default=[]) 26 | 27 | ascent = Number(default=None) 28 | descent = Number(default=None) 29 | capHeight = Number(default=None) 30 | 31 | stemV = Number(default=None) 32 | defaultWidth = Number(default=None) 33 | widths = List(default=[]) 34 | cmap = Dict(default={}) 35 | 36 | @property 37 | def flags(self): 38 | """ 39 | See Section 9.8.2 - Font Descriptor Flags of PDF 1.7 Spec 40 | Bit 1 - FixedPitch 41 | Bit 2 - Serif 42 | Bit 3 - Symbolic 43 | Bit 4 - Script 44 | Bit 6 - Nonsymbolic 45 | Bit 7 - Italic 46 | Bit 17 - AllCap 47 | Bit 18 - SmallCap 48 | Bit 19 - ForceBold 49 | :return: 50 | """ 51 | flags = 4 52 | if self.italicAngle != 0: 53 | flags = flags | 64 54 | if self.usWeightClass >= 600: 55 | flags = flags | 262144 56 | if self.isFixedPitch: 57 | flags = flags | 1 58 | return flags 59 | -------------------------------------------------------------------------------- /endesive/pdf/fpdf/php.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: latin-1 -*- 3 | 4 | from .py3k import PY3K, basestring, unicode 5 | 6 | # fpdf php helpers: 7 | 8 | def substr(s, start, length=-1): 9 | if length < 0: 10 | length=len(s)-start 11 | return s[start:start+length] 12 | 13 | def sprintf(fmt, *args): return fmt % args 14 | 15 | def print_r(array): 16 | if not isinstance(array, dict): 17 | array = dict([(k, k) for k in array]) 18 | for k, v in array.items(): 19 | print("[%s] => %s " % (k, v)) 20 | 21 | def UTF8ToUTF16BE(instr, setbom=True): 22 | "Converts UTF-8 strings to UTF16-BE." 23 | outstr = "".encode() 24 | if (setbom): 25 | outstr += "\xFE\xFF".encode("latin1") 26 | if not isinstance(instr, unicode): 27 | instr = instr.decode('UTF-8') 28 | outstr += instr.encode('UTF-16BE') 29 | # convert bytes back to fake unicode string until PEP461-like is implemented 30 | if PY3K: 31 | outstr = outstr.decode("latin1") 32 | return outstr 33 | 34 | def UTF8StringToArray(instr): 35 | "Converts UTF-8 strings to codepoints array" 36 | return [ord(c) for c in instr] 37 | 38 | # ttfints php helpers: 39 | 40 | def die(msg): 41 | raise RuntimeError(msg) 42 | 43 | def str_repeat(s, count): 44 | return s * count 45 | 46 | def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ): 47 | if pad_type<0: # pad left 48 | return s.rjust(pad_length, pad_char) 49 | elif pad_type>0: # pad right 50 | return s.ljust(pad_length, pad_char) 51 | else: # pad both 52 | return s.center(pad_length, pad_char) 53 | 54 | strlen = count = lambda s: len(s) 55 | -------------------------------------------------------------------------------- /LICENSE.pypdf2: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2008, Mathieu Fenniak 2 | Some contributions copyright (c) 2007, Ashish Kulkarni 3 | Some contributions copyright (c) 2014, Steve Witham 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | * The name of the author may not be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-twice-1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 8192, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | # "sigbutton": True, 25 | "sigfield": "Signature1", 26 | "auto_sigfield": True, 27 | "sigandcertify": True, 28 | "signaturebox": (470, 840, 570, 640), 29 | "signature": "Podpis 1", 30 | # "signature_img": "signature_test.png", 31 | "contact": "demo1@demot.com.pl", 32 | "location": "Szczecin", 33 | "signingdate": date, 34 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 35 | "password": "1234", 36 | } 37 | with open("ca/demo2_user1.p12", "rb") as fp: 38 | p12 = pkcs12.load_key_and_certificates( 39 | fp.read(), b"1234", backends.default_backend() 40 | ) 41 | fname = "pdf.pdf" 42 | if len(sys.argv) > 1: 43 | fname = sys.argv[1] 44 | datau = open(fname, "rb").read() 45 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 46 | fname = fname.replace(".pdf", "-signed-cms-twice-1.pdf") 47 | with open(fname, "wb") as fp: 48 | fp.write(datau) 49 | fp.write(datas) 50 | 51 | 52 | main() 53 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-twice-2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 8192, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | # "sigbutton": True, 25 | "sigfield": "Signature1", 26 | "auto_sigfield": True, 27 | "sigandcertify": True, 28 | "signaturebox": (470, 640, 570, 440), 29 | "signature": "Podpis 2", 30 | # "signature_img": "signature_test.png", 31 | "contact": "contact:demo2@demot.com.pl", 32 | "location": "Szczecin", 33 | "signingdate": date, 34 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 35 | "password": "1234", 36 | } 37 | with open("ca/demo2_user2.p12", "rb") as fp: 38 | p12 = pkcs12.load_key_and_certificates( 39 | fp.read(), b"1234", backends.default_backend() 40 | ) 41 | fname = "pdf-signed-cms-twice-1.pdf" 42 | if len(sys.argv) > 1: 43 | fname = sys.argv[1] 44 | datau = open(fname, "rb").read() 45 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 46 | fname = fname.replace("1", "2") 47 | with open(fname, "wb") as fp: 48 | fp.write(datau) 49 | fp.write(datas) 50 | 51 | 52 | main() 53 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-twice-end.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 8192, 21 | "sigflags": 1, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | # "sigbutton": True, 25 | "sigfield": "Signature1", 26 | "auto_sigfield": True, 27 | "sigandcertify": True, 28 | "signaturebox": (470, 440, 570, 240), 29 | "signature": "Podpis 3", 30 | # "signature_img": "signature_test.png", 31 | "contact": "contact:demo3@demot.com.pl", 32 | "location": "Szczecin", 33 | "signingdate": date, 34 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 35 | "password": "1234", 36 | } 37 | with open("ca/demo2_user3.p12", "rb") as fp: 38 | p12 = pkcs12.load_key_and_certificates( 39 | fp.read(), b"1234", backends.default_backend() 40 | ) 41 | fname = "pdf-signed-cms-twice-2.pdf" 42 | if len(sys.argv) > 1: 43 | fname = sys.argv[1] 44 | datau = open(fname, "rb").read() 45 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 46 | fname = fname.replace("2", "end") 47 | with open(fname, "wb") as fp: 48 | fp.write(datau) 49 | fp.write(datas) 50 | 51 | 52 | main() 53 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 8192, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | # "sigbutton": True, 25 | # "sigfield": "Signature1", 26 | # "auto_sigfield": True, 27 | # "sigandcertify": True, 28 | # "signaturebox": (470, 840, 570, 640), 29 | "signature": "Dokument podpisany cyfrowo ąćęłńóśżź", 30 | # "signature_img": "signature_test.png", 31 | "contact": "contact:mak@trisoft.com.pl", 32 | "location": "Szczecin", 33 | "signingdate": date, 34 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 35 | "password": "1234", 36 | } 37 | with open("ca/demo2_user1.p12", "rb") as fp: 38 | p12 = pkcs12.load_key_and_certificates( 39 | fp.read(), b"1234", backends.default_backend() 40 | ) 41 | fname = "pdf.pdf" 42 | if len(sys.argv) > 1: 43 | fname = sys.argv[1] 44 | datau = open(fname, "rb").read() 45 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 46 | fname = fname.replace(".pdf", "-signed-cms.pdf") 47 | with open(fname, "wb") as fp: 48 | fp.write(datau) 49 | fp.write(datas) 50 | 51 | 52 | main() 53 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "endesive" 7 | description = "Library for digital signing and verification of digital signatures in mail, PDF and XML documents." 8 | authors = [{ name = "Grzegorz Makarewicz", email = "mak@trisoft.com.pl" }] 9 | maintainers = [{ name = "Grzegorz Makarewicz", email = "mak@trisoft.com.pl" }] 10 | readme = "README.rst" 11 | version = "2.19.2" 12 | license = "MIT" 13 | license-files = ["LICENSE", "LICENSE.pdf-annotate", "LICENSE.pyfpdf", "LICENSE.pypdf2"] 14 | requires-python = ">=3.0" 15 | classifiers = [ 16 | "Development Status :: 4 - Beta", 17 | "Development Status :: 5 - Production/Stable", 18 | "Operating System :: OS Independent", 19 | "Intended Audience :: Developers", 20 | "Programming Language :: Python :: 3", 21 | "Topic :: Software Development :: Libraries :: Python Modules", 22 | "Topic :: Communications :: Email", 23 | "Topic :: Security :: Cryptography", 24 | "Topic :: Office/Business", 25 | "Topic :: Text Processing", 26 | "Topic :: Multimedia :: Graphics", 27 | ] 28 | 29 | [project.urls] 30 | Source = "https://github.com/m32/endesive" 31 | "Bug Reports" = "https://github.com/m32/endesive/issues" 32 | 33 | [project.optional-dependencies] 34 | full = [ 35 | "cryptography", 36 | "asn1crypto", 37 | "lxml", 38 | "pykcs11", 39 | "Pillow", 40 | "requests", 41 | "paramiko" 42 | ] 43 | 44 | dev = [ 45 | "pytest-cov", 46 | "wheel" 47 | ] 48 | docs = [ 49 | "sphinx", 50 | "sphinx_rtd_theme" 51 | ] 52 | 53 | [tool.check-wheel-contents] 54 | package = "./endesive" 55 | 56 | [tool.pytest.ini_options] 57 | filterwarnings = ["error"] 58 | testpaths = ["tests"] 59 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-m32-unizeto.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography import x509 6 | from cryptography.hazmat import backends 7 | from cryptography.hazmat.primitives.serialization import pkcs12 8 | from endesive import pdf 9 | 10 | # import logging 11 | # logging.basicConfig(level=logging.DEBUG) 12 | 13 | 14 | def main(): 15 | tspurl = "http://time.certum.pl" 16 | #tspurl = "http://public-qlts.certum.pl/qts-17" 17 | date = datetime.datetime.utcnow() 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "sigflags": 3, 21 | "sigpage": 0, 22 | "sigbutton": False, 23 | "name": "Grzegorz Makarewicz", 24 | "contact": "mak@trisoft.com.pl", 25 | "location": "Szczecin", 26 | "signingdate": date.encode(), 27 | "reason": "Dokument podpisany cyfrowo", 28 | "sigandcertify": False, 29 | "ltv": True, 30 | } 31 | 32 | pk12fname = "/home/mak/Dokumenty/m32/ssl/unizeto/unizeto.p12" 33 | pk12pass = sys.argv[1].encode() 34 | with open(pk12fname, "rb") as fp: 35 | p12 = pkcs12.load_key_and_certificates( 36 | fp.read(), pk12pass, backends.default_backend() 37 | ) 38 | 39 | fname = "pdf.pdf" 40 | if len(sys.argv) > 2: 41 | fname = sys.argv[2] 42 | datau = open(fname, "rb").read() 43 | datas = pdf.cms.sign( 44 | datau, 45 | dct, 46 | p12[0], 47 | p12[1], 48 | p12[2][:3], 49 | "sha256", 50 | None, 51 | tspurl 52 | ) 53 | fname = fname.replace(".pdf", "-signed-cms-m32-unizeto.pdf") 54 | with open(fname, "wb") as fp: 55 | fp.write(datau) 56 | fp.write(datas) 57 | 58 | 59 | main() 60 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-m32-actalis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography import x509 6 | from cryptography.hazmat import backends 7 | from cryptography.hazmat.primitives.serialization import pkcs12 8 | from endesive import pdf 9 | 10 | # import logging 11 | # logging.basicConfig(level=logging.DEBUG) 12 | 13 | 14 | def main(): 15 | date = datetime.datetime.utcnow() - datetime.timedelta() 16 | date = date.strftime("%Y%m%d%H%M%S+00'00'") 17 | dct = { 18 | "sigflags": 3, 19 | "sigpage": 0, 20 | "sigbutton": True, 21 | "contact": "mak@trisoft.com.pl", 22 | "location": "Szczecin", 23 | "signingdate": date.encode(), 24 | "reason": "Dokument podpisany cyfrowo", 25 | "signature": "Dokument podpisany cyfrowo", 26 | "signaturebox": (0, 0, 100, 100), 27 | "sigandcertify": True, 28 | "text": { 29 | "fontsize": 10, 30 | }, 31 | } 32 | 33 | pk12fname = "/home/mak/Dokumenty/m32/ssl/actalis/actalis.p12" 34 | pk12pass = sys.argv[1].encode() 35 | with open(pk12fname, "rb") as fp: 36 | p12 = pkcs12.load_key_and_certificates( 37 | fp.read(), pk12pass, backends.default_backend() 38 | ) 39 | 40 | fname = "pdf.pdf" 41 | if len(sys.argv) > 2: 42 | fname = sys.argv[2] 43 | datau = open(fname, "rb").read() 44 | datas = pdf.cms.sign( 45 | datau, 46 | dct, 47 | p12[0], 48 | p12[1], 49 | p12[2][:3], 50 | "sha256", 51 | None, 52 | ) 53 | fname = fname.replace(".pdf", "-signed-cms-m32-actalis.pdf") 54 | with open(fname, "wb") as fp: 55 | fp.write(datau) 56 | fp.write(datas) 57 | 58 | 59 | main() 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | examples/endesive 107 | examples/*.txt 108 | examples/*.pdf 109 | examples/*.xml 110 | .idea/ 111 | -------------------------------------------------------------------------------- /examples/ca/demo2_user1.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-256-CBC,13CA42E4D2AB6F9EE44A8ECD4FC53348 4 | 5 | ZQfwakGfrfP4lMZJVUww1q4OGVrRsZf4V/iJr66lJLqDp27SEBIqYFbW65ds3lYI 6 | C32CLwrjtdSL8ABuaAd9jXiIX/XuTIIfokg6TuKZUXgagCCIAn7vh1fp9WJiipGH 7 | 6La8gFCuD9rJBP2GgCS/W74lKNxgfuryHvmpRdKpLQBjvOtjpffQxSpB0oOEkf3e 8 | UoJJyzgZhmuJXHPUsBHKknINwj+n6gwOnh7YRbR1VGQTHM6uopp9hpguphk9lP3t 9 | /z7i6hKPC1uLvkleiE20ic7JVxebPkKtMoZj/7LVHZ0PDCj5QOxPmfc5lpvLyj2E 10 | HoPOsJM9LkLUefaj1xzg3qWZx6rre3fYqWGUruqKgjy9niVlUB6JXV88YOU5onQc 11 | 23imLM1dUB+E53cWe+oxOUsqTbnbW2Pw3cCNHzFqWXHwFGmRk7e3bnp3rRD2DpBW 12 | mCJmqYqpPL0QSFPs1w5WLS+/beFRJHkTd7mNJMTKuur2l27enZzqw8NaJ89cNZPE 13 | uLW1fwlejSP0n6JBw1DiNSc50FKLeE089jM7f9nLwbOFxpEo0ZEYsMZcFyEVqYP+ 14 | QX/bd+uHS8OFXUIpVR2brjYgQK+XNPBXejxGPJIfzj6CRH3cwhVUiMlAKdgt21Wt 15 | mGbIDS0nfvZNlB5zfV33EiCSQGgG3lDst3kS1UUf78GgsuvTnuNbChc28VgAvYG6 16 | jTZsSKNHd1Jls+Wbx7fm11sq5EoJpYtXiKQoVz13Xi99LTTTdFZFW3yMkwlbVf25 17 | h5Y4Gv9OW4BPyCQpHpK11ubWuHzNjud2XDb4syKpK2a6EGPWOfS+Kc9J9q5f9qKN 18 | 2vGGuRKQoSEEn3mnGGdwULvA2yj9kATkt57uge7xLYO4YyTeZJESx4/ruaF6FJOg 19 | didGM4h0Xh78UB6mN5PPmxXTYx5CQ3E3JPbfyWPRT3a6JAnyTHLtJNBPxCBHo2PA 20 | zEX9tGRyH5iA7XSllxvK7VhKrtI1dEBbwvCoXr77mZbBiva/IRzdPtjpwS8zZBsU 21 | CJAZsz1Y7B0cZ97VPg9zSwxs8nCsZhemOml5/gpwoXuGmX7jK6IEvVojrI/RlkSD 22 | 9ktNKgzxCjHlHYW4mUkcFOYqdQnqxn4YIiHE1PaqGlT/7u7QSVkksagaSnLT/vyd 23 | PnExNwUNR2eG256ZB7oS4glm3HlwWk9svpUo2C05uZP126eoyvafiTWLr7axX94G 24 | I5LlPeB+wwELef2bPvq0WjLklSPqNRBbopNZvtrWXzn0zSBz/kDzjsQtEoSRZU5I 25 | DABLStYuy863VGdnqf5uEhdStKyKjnetJaGxOXJMkS+oJUOUSiGYztdg22tcK7Kp 26 | yuX0qe3xirIF3YcIaQOnHQTJ4Yqjm1q/sTwj3jkuqdtH5b3zs8BzRkbR81zCmFkH 27 | MNsuGwF1GhUVmYS1wMvtUG4w9c9s44sLPoiJhMNNrycJREXnIMAe9yztZX2PQaey 28 | zOcOzX3yIJ6N9Ob9K0l0R+89nrPEDJbXQRwjbhuWlmMvZY3KQM3+VgMJtJDL11In 29 | 7LqeEyRno5ojyUN8XVovExqPHzr3HcAx3twf0mquhYgzbuIGVpe0LT2FFrkOTkYy 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /examples/ca/demo2_user2.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-256-CBC,432E91A73338F65EF028B48F7A75C8D5 4 | 5 | 9s4U5Cwn9ajLjX42GuoOrhsbBWSWofZ7XMt+08UkVagWoKUbxIjOv4BKhF5AUDtq 6 | lPneYDiZNNNx8wKrI/okPGBrE4ftfGZC414Xb/EpgVIr+H4JutIcR04H3xWUHYUI 7 | +6oE6SD/vD6XTzAMMgpHU43hKnLRHE8Utyfk+v4wlCl/O8oLHVWdK0jD7r0bq4vp 8 | CqbWJd8y3GbeYvaoke5CCOH9fEW50vLlcwFewrf6y8NBINyPf0JM/Puju8W+7DR+ 9 | MgK/9vtdxVnX+RAs/0i2T5tehklQxZhfJC3YEbUCjdZPgtNRFVWpbRnpzCXFYFJX 10 | dpKX1WuINGpcQk8BJ3KLDUOrv3nqHyUshQ6MCcRUTr+gvAAV7Nr3y3MowqfwD8QX 11 | p8QoIqFVFDtwvQAePb8VrMqizMqAzmaOWE2sA3Vd0pAPZZncXcFbwMwK3TM3aUwR 12 | EuvasRgJ7ujiDXMJS35P53js+yNduFRi0W5C5kEGsMQs8GtAEJ2j65nEfONx0nzS 13 | AKHJNH8XTvVzIwcf1SU0dA34Bl37h90X/xFbkxZ5Z7EnZidbXuOOJ9tqVNFPi4Xh 14 | is9v/1gAz2VXMWywkDAVz0o194veM2ynuBamF3mxJD+NKHp6t3Qf/6FGBPUD/yOL 15 | AT/1o+z/OwGSm/DHM47jhUArx4A5ATLZ0CbpE6ViRfsFv/YiQXVK0AmFQQNi5fca 16 | QdVdz9DGFqWa4Q2sSYPcAa7b0iwZ5QSWJmYmKzQ2oDER4G+qxpx4t20D/ipB1FD/ 17 | FDjsf9M3fEktoqSvLZdUzs3J59VMyESMwfnj7RV12EUOea4lfpxWW7t0DkJiLMkE 18 | Kp2yvvdYr5zSt5Gfz+WOhU6Fsmql7w4ONYLZxx/64hrcL5IFgPn0fgJZudU15xJd 19 | uApZ4i9qo2PtBO/I6kTKB8l/fUzCSIyzunRefO2YHlNoJ8yIVJpBd/f36j+m2LqJ 20 | BukwxetYLGdBX+jPdspXUUJc2YeKjJJsYoGcOQqozn5fS1CmvnWr3mElZuCix4JZ 21 | aI7eueFXxNKBh6YjLOItgGb6p8hS4zbdhr1rbB4qxB6tqgnfjikfGKhogAJ8TTTB 22 | nn5SvPcvyV+o4Qyyn7OktRHQkYv5vM76gwymQjsCYpBTjyYMUsDdXkfO40AIcXoN 23 | XDbM9OSyfwpuxlvN6t94IdnXdEnFTDEA8F6SWA3ILlv2kMW+4We3HTaRJERPj0Zx 24 | B2FdzHsYgG2mAsWbls0qP7M+NTVtT6k1tMCn7aNrKv1Wxt4vkrJRFT7JWA9zq07q 25 | KLZWJSDic1tkykURYnNbjkgsS3kAb6w5doSqZT9mDXJS9FE52UVNHDRhFmUa+myN 26 | FtgSeJ7be86wxcpV4xkc3ylZrmzC2yVMeySmm66mpPf3Cox/VGN+xByv9rS18KgN 27 | Su1vpjn+GXPsUZGklURmKgG9cIvW4eOvsTcYZomH6ef9VC06t+P4u18C03ZkkGiu 28 | 3pI0I16piBAA+z9w2mf4AWiXLOVQ2+85nyHFOnyStKSR1/AX5cmLPVkoklfDhp8A 29 | DAKDe1cIpIqyqDXIIJIhQKpZSNdRKzDm9Hs24106+4EnHdGmJtpl0wiGS2m0lPts 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /examples/ca/demo2_user3.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-256-CBC,6F74D43BFD983962443F8AA7E7B1474A 4 | 5 | O8kOPAT5Z3Ljy2cO5YHA6iPTlxZ9ES0RdhhT2liz6umjf07LksNPAfTY4uUvD6Qf 6 | dYuCxLCBiMhwEb2TH2m3kbKRPUNOGK9qWTsTNUMndL9m7SE3onagmmqNAwyvF/Kj 7 | 91kgcGU/lBPzJ+twVnN+1Zsy8uQysf48ousNZMjTTAx7kw7SEHer/oEVu7YeD28E 8 | tE4dWOxR3wC0wFWOZzjBPv9GSCDu1t5yn7r+ccTTE9CcvCbuZp1x/vtO0ALclQp3 9 | befpgoCHeq/15MNSPRQdTf4ffWzgzTbP+1hyZfkGRDMYxjn3L4mRpJNfGqoxkb01 10 | i5Fv810IFMf8qDmcKRI2jeh4BO5G1MKZhuiV//uyqYWfe8IU+2JKcLQ7lCHUrfPP 11 | 7HlV7tyvp24tScvRttAMvdfXWpGPZWyWbu4VxRrgK7T8F/zIWKpUhpuRl+mkLApa 12 | YM4mYXDRB16olk7pfWwDrYw8bonvlGQMCYZ+ZylhcSPmDdkxk7XsI30cfh2iHcSb 13 | UGsLcAuGM8l9ouemh7N1Q73VnV67Ln3L3G1os96au5fCEsh9Yeyykw3haBIvN5ip 14 | c+EGR/9pE4e9Dm6mjBwYvSo/smRHm4HvHs/h1Na6QtWm2/gjS16iNlb0O7CJQxkb 15 | +v+w1EyBZeME/gawVqdPw26U5o9sQCEnLxVJJ+ANx8UyR08brDUU/owrcBNyzlBt 16 | BL6Exqe7vFhMyEEmodZUvJG+Xi6N1EOYo1yrWeQto+cyVr/PhWpculQaroKvCC9L 17 | oZTyZiKcJhiHYDrgR20I0HWyySta4iSnhYrMeySlc6k6WFUx6HiG0Aln9x7Fx5ca 18 | 39r/deT2d1ixYyUmX5aqdIcAAqJGcjW5VAanxx4BeRBNhmFG4Ll0PNMLARg5p2kC 19 | D96ny4+n20CQmdhHQ+IfPCc2oaw8mavOR5e+RWwasqbHp8GBU6IYJ2rW8MW0FcYZ 20 | SFa3MtevQQS7algofOnmoiV5Hobn/p82j0MQXSd8L02shLplPcPfo3fy0UFCDRMz 21 | zJf1aokh3hT7nTQYNE6t0qxXc3bYyCpW3dof+LAyj8Q6pMalppPatVODx1n/PM9e 22 | AFiX2wqjN9Ud4EUHRrwoIitdDjjDeug68GDA1Cnyacd4JLmS5q6KMOjDQ9Y0HRiz 23 | Emw5S3li0gD0Gr4YhfFMEjzgwnOqC3LCLcYg6JeRcPBpBfIquRvxy4S+yC2ibQ9m 24 | qYhUSxYoIEkqVGRWk8C3aFTVagl3/fvw2llkVwmhozyLSWECprVa+haXICY6iO3q 25 | kx67WgjXAAQ08vwl0M+A4JZOSMuJM9/eilTwoKaaVZnLR+XY0/0RA9RvqRrgIwas 26 | 3h2NJlnkp4ihQzqMnqUoHFF+jB20rlnMg/w1MlxBLE2c2j9GfwfjPpKGJZ7gZHcE 27 | j1lVp7I4SEcGIPVzWJ6UsY2EE23X7AwAXEzePOiHkyJvPzAXIC2cyCafPmA64Gwe 28 | SSIIwDpJdjMIsoipU8oexTssJIFxScIrh/46xWTAyvqk2tbJ+74HGDIYx2VbOTpe 29 | quSJf55a0xIP+o4/nulypuS5B7n7q295GrAjsfkj4F+0cvgfyoOQtFy0BjwSmWm0 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/pdfrw.py: -------------------------------------------------------------------------------- 1 | from endesive.pdf.PyPDF2 import generic as pdf 2 | 3 | 4 | def makeObject(obj): 5 | if isinstance(obj, pdf.PdfObject): 6 | return obj 7 | if isinstance(obj, int): 8 | return pdf.NumberObject(obj) 9 | if isinstance(obj, float): 10 | return pdf.NumberObject(obj) 11 | if isinstance(obj, str): 12 | return pdf.createStringObject(obj) 13 | if isinstance(obj, (list, tuple)): 14 | result = pdf.ArrayObject() 15 | for v in obj: 16 | v = makeObject(v) 17 | result.append(v) 18 | return result 19 | if isinstance(obj, dict): 20 | result = PdfDict() 21 | for k, v in obj.items(): 22 | v = makeObject(v) 23 | result[k] = v 24 | return result 25 | raise ValueError("can`t convert to PdfObject", obj) 26 | 27 | 28 | class PdfDict(pdf.DictionaryObject): 29 | indirect = False 30 | stream = None 31 | 32 | def __init__(self, *args, **kwargs): 33 | super(PdfDict, self).__init__({}) 34 | for k, v in kwargs.items(): 35 | self[k] = v 36 | 37 | def __setitem__(self, k, v): 38 | if k == "stream": 39 | if isinstance(v, str): 40 | v = v.encode("latin1") 41 | self.stream = v 42 | return 43 | if not isinstance(k, pdf.NameObject): 44 | k = PdfName(k) 45 | v = makeObject(v) 46 | super(PdfDict, self).__setitem__(k, v) 47 | 48 | 49 | class IndirectPdfDict(PdfDict): 50 | indirect = True 51 | 52 | 53 | def PdfName(name): 54 | return pdf.NameObject("/" + name) 55 | 56 | 57 | def PdfString(s): 58 | return pdf.createStringObject(s) 59 | 60 | 61 | def PdfArray(l): 62 | result = pdf.ArrayObject([]) 63 | for v in l: 64 | v = makeObject(v) 65 | result.append(v) 66 | return result 67 | -------------------------------------------------------------------------------- /endesive/pdf/fpdf/py3k.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | "Special module to handle differences between Python 2 and 3 versions" 5 | 6 | import sys 7 | 8 | PY3K = sys.version_info >= (3, 0) 9 | 10 | try: 11 | import cPickle as pickle 12 | except ImportError: 13 | import pickle 14 | 15 | try: 16 | from urllib import urlopen 17 | except ImportError: 18 | from urllib.request import urlopen 19 | 20 | try: 21 | from hashlib import md5 22 | except ImportError: 23 | try: 24 | from md5 import md5 25 | except ImportError: 26 | md5 = None 27 | def hashpath(fn): 28 | h = md5() 29 | if PY3K: 30 | h.update(fn.encode("UTF-8")) 31 | else: 32 | h.update(fn) 33 | return h.hexdigest() 34 | 35 | # Check if PIL is available (tries importing both pypi version and corrected or manually installed versions). 36 | # Necessary for JPEG and GIF support. 37 | # TODO: Pillow support 38 | try: 39 | from PIL import Image 40 | except ImportError: 41 | try: 42 | import Image 43 | except ImportError: 44 | Image = None 45 | 46 | try: 47 | from HTMLParser import HTMLParser 48 | except ImportError: 49 | from html.parser import HTMLParser 50 | 51 | if PY3K: 52 | basestring = str 53 | unicode = str 54 | ord = lambda x: x 55 | else: 56 | basestring = basestring 57 | unicode = unicode 58 | ord = ord 59 | 60 | # shortcut to bytes conversion (b prefix) 61 | def b(s): 62 | if isinstance(s, basestring): 63 | return s.encode("latin1") 64 | elif isinstance(s, int): 65 | if PY3K: 66 | return bytes([s]) # http://bugs.python.org/issue4588 67 | else: 68 | return chr(s) 69 | 70 | def exception(): 71 | "Return the current the exception instance currently being handled" 72 | # this is needed to support Python 2.5 that lacks "as" syntax 73 | return sys.exc_info()[1] 74 | 75 | 76 | -------------------------------------------------------------------------------- /examples/pdf-verify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from endesive import pdf 4 | 5 | 6 | def main(): 7 | trusted_cert_pems = ( 8 | # demo ca chain 9 | open("ca/demo2_ca.root.crt.pem", "rb").read(), 10 | # demo hsm ca chain 11 | #open("cert-hsm-ca.pem", "rb").read(), 12 | ) 13 | for fname in ( 14 | #"test-PDFXRef-signed-cms.pdf", 15 | #"test-PDFXRefStream-signed-cms.pdf", 16 | #"test-SHA256_RSA-signed-cms.pdf", 17 | #"pdf-acrobat.pdf", 18 | #"pdf-signed-cms-hsm-certum.pdf", 19 | #"pdf-signed-cms-hsm.pdf", 20 | 21 | "pdf-signed-cms.pdf", 22 | "pdf-signed-cms-hash.pdf", 23 | "pdf-signed-cms-ltv.pdf", 24 | "pdf-signed-cms-m32-actalis.pdf", 25 | "pdf-signed-cms-m32-unizeto.pdf", 26 | "pdf-signed-cms-pfx.pdf", 27 | "pdf-signed-cms-pil.pdf", 28 | "pdf-signed-cms-pypdf.pdf", 29 | "pdf-signed-cms-twice-1.pdf", 30 | "pdf-signed-cms-twice-2.pdf", 31 | "pdf-signed-cms-twice-end.pdf", 32 | "pdf-signed-fpdf.pdf", 33 | 34 | #"pdf-signed-java.pdf", 35 | #"pdf-signed-pypdf.pdf", 36 | #"pdf-encrypted-signed-java.pdf", 37 | #"pdf-encrypted-signed-pypdf.pdf", 38 | #"pdf-link-signed-java.pdf", 39 | #"pdf-link-signed-pypdf.pdf", 40 | ): 41 | print("*" * 20, fname) 42 | try: 43 | data = open(fname, "rb").read() 44 | except: 45 | print('skip') 46 | continue 47 | no = 0 48 | try: 49 | for (hashok, signatureok, certok) in pdf.verify( 50 | data, trusted_cert_pems 51 | ): 52 | print("*" * 10, "signature no:", no) 53 | print("signature ok?", signatureok) 54 | print("hash ok?", hashok) 55 | print("cert ok?", certok) 56 | except Exception as exc: 57 | print(exc) 58 | 59 | main() 60 | -------------------------------------------------------------------------------- /examples/signature_appearances/signature_img.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 0, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | #"auto_sigfield": False, 25 | #"sigandcertify": False, 26 | #"signaturebox": (0, 0, 590, 155), 27 | "signform": True, 28 | "sigfield": "Signature", 29 | # PIL Image object or path to image file 30 | # Image will be resized to fit bounding box 31 | "signature_img": '../signature_test.png', 32 | "signature_img_distort": False, # default True 33 | "signature_img_centred": False, # default True 34 | 35 | "contact": "mak@trisoft.com.pl", 36 | "location": "Szczecin", 37 | "signingdate": date, 38 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 39 | "password": "1234", 40 | } 41 | with open("../ca/demo2_user1.p12", "rb") as fp: 42 | p12 = pkcs12.load_key_and_certificates( 43 | fp.read(), b"1234", backends.default_backend() 44 | ) 45 | fname = "../pdf_forms/blank_form.pdf" 46 | if len(sys.argv) > 1: 47 | fname = sys.argv[1] 48 | datau = open(fname, "rb").read() 49 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 50 | fname = fname.replace(".pdf", "-signature_img.pdf") 51 | with open(fname, "wb") as fp: 52 | fp.write(datau) 53 | fp.write(datas) 54 | 55 | 56 | main() 57 | -------------------------------------------------------------------------------- /examples/signature_appearances/signature.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 0, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | #"auto_sigfield": False, 25 | #"sigandcertify": False, 26 | #"signaturebox": (0, 0, 590, 155), 27 | "signform": True, 28 | "sigfield": "Signature", 29 | # Text will be in the default font 30 | "signature": 'Signed field!', 31 | 32 | # default configuration for the text appearance 33 | "text": { 34 | 'wraptext': True, 35 | 'fontsize': 12, 36 | 'textalign': 'left', 37 | 'linespacing': 1.2, 38 | }, 39 | 40 | "contact": "mak@trisoft.com.pl", 41 | "location": "Szczecin", 42 | "signingdate": date, 43 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 44 | "password": "1234", 45 | } 46 | with open("../ca/demo2_user1.p12", "rb") as fp: 47 | p12 = pkcs12.load_key_and_certificates( 48 | fp.read(), b"1234", backends.default_backend() 49 | ) 50 | fname = "../pdf_forms/blank_form.pdf" 51 | if len(sys.argv) > 1: 52 | fname = sys.argv[1] 53 | datau = open(fname, "rb").read() 54 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 55 | fname = fname.replace(".pdf", "-signature.pdf") 56 | with open(fname, "wb") as fp: 57 | fp.write(datau) 58 | fp.write(datas) 59 | 60 | 61 | main() 62 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hsm-windows.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import datetime 3 | from win32 import win32crypt 4 | from win32.lib import win32cryptcon 5 | 6 | from endesive import hsm, pdf 7 | 8 | class WindowsHSM(hsm.BaseHSM): 9 | def __init__(self, subject, certstore='MY'): 10 | self.derdata = None 11 | self.cert = None 12 | 13 | st = win32crypt.CertOpenSystemStore(certstore, None) 14 | try: 15 | certs = st.CertEnumCertificatesInStore() 16 | for cert in certs: 17 | if win32crypt.CertNameToStr(cert.Subject) == subject: 18 | self.derdata = cert.CertEncoded 19 | self.cert = cert 20 | break 21 | finally: 22 | st.CertCloseStore() 23 | 24 | def certificate(self): 25 | return 1, self.derdata 26 | 27 | def sign(self, keyid, data, mech): 28 | keyspec, cryptprov = self.cert.CryptAcquireCertificatePrivateKey(win32cryptcon.CRYPT_ACQUIRE_COMPARE_KEY_FLAG) 29 | chash = cryptprov.CryptCreateHash(win32cryptcon.CALG_SHA1, None, 0) 30 | chash.CryptHashData(data, 0) 31 | res = chash.CryptSignHash(keyspec, 0) 32 | return res[::-1] 33 | 34 | def main(): 35 | clshsm = WindowsHSM('USER 1') 36 | 37 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 38 | date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') 39 | dct = { 40 | 'sigflags': 3, 41 | 'contact': 'user@example.com', 42 | 'location': 'England', 43 | 'signingdate': date.encode(), 44 | 'reason': 'Test', 45 | } 46 | fname = 'pdf.pdf' 47 | if len (sys.argv) > 1: 48 | fname = sys.argv[1] 49 | datau = open(fname, 'rb').read() 50 | datas = pdf.cms.sign(datau, dct, 51 | None, None, 52 | [], 53 | 'sha1', 54 | clshsm, 55 | ) 56 | fname = fname.replace('.pdf', '-signed-cms-hsm-windows.pdf') 57 | with open(fname, 'wb') as fp: 58 | fp.write(datau) 59 | fp.write(datas) 60 | 61 | main() 62 | -------------------------------------------------------------------------------- /examples/pdf-verifier.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | from endesive.pdf import PDFVerifier 4 | 5 | 6 | def main(): 7 | trustedcerts = [] 8 | with open("nccert2016.crt.pem", "rb") as fp: 9 | trustedcerts.append(fp.read()) 10 | with open("ca/demo2_ca.root.crt.pem", "rb") as fp: 11 | trustedcerts.append(fp.read()) 12 | 13 | if len(sys.argv) > 1: 14 | fname = sys.argv[1] 15 | else: 16 | fname = "pdf-signed-cms-m32-unizeto.pdf" 17 | with open(fname, "rb") as fp: 18 | pdf_data = fp.read() 19 | 20 | v = PDFVerifier(pdf_data, trustedcerts) 21 | 22 | if not v.is_valid_pdf(): 23 | print(f"{fname} is not a pdf file") 24 | return 25 | 26 | if not v.is_signed(): 27 | if v.modified: 28 | print(f"file {fname} is modified") 29 | else: 30 | print(f"file {fname} is unsigned") 31 | if not v.wholefile: 32 | print("the signature does not cover the entire pdf file") 33 | return 34 | 35 | (signed_data, tspdata, crldata, cert, othercerts, hashok, signatureok) = v.decompose_signature() 36 | if not hashok or not signatureok: 37 | print(f"file {fname} is modified") 38 | return 39 | 40 | certok = v.validate_certificate(cert, othercerts) 41 | if not certok: 42 | print(f"signing certificate is invalid") 43 | return 44 | 45 | print(f"signed with cert serial_number: {cert.serial_number}") 46 | print("other certificates:") 47 | for ocert in othercerts: 48 | print(f" serial_number: {ocert.serial_number}") 49 | 50 | if crldata.native is not None: 51 | ok, info = v.verify_ocsp_data(cert, othercerts, crldata) 52 | if ok: 53 | print(f'ocsp issued at: {info[0]}, next check at: {info[1]}') 54 | else: 55 | print(f'ocsp is invalid') 56 | 57 | if tspdata is not None: 58 | ok, info = v.verify_tsp_data(signed_data, tspdata, othercerts) 59 | if ok: 60 | print(f'tsp issued at: {info}') 61 | else: 62 | print(f'tsp is invalid') 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /examples/nccert2016.crt.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFzzCCA7egAwIBAgIUQPj3irDjZBBWkcjZ4Cz4wcZACkYwDQYJKoZIhvcNAQEN 3 | BQAwbzELMAkGA1UEBhMCUEwxHTAbBgNVBAoMFE5hcm9kb3d5IEJhbmsgUG9sc2tp 4 | MSYwJAYDVQQDDB1OYXJvZG93ZSBDZW50cnVtIENlcnR5ZmlrYWNqaTEZMBcGA1UE 5 | YQwQVkFUUEwtNTI1MDAwODE5ODAeFw0xNjEyMDkwODUyNDFaFw0zOTEyMDkyMzU5 6 | NTlaMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJvZG93eSBCYW5rIFBvbHNr 7 | aTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0eWZpa2FjamkxGTAXBgNV 8 | BGEMEFZBVFBMLTUyNTAwMDgxOTgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 9 | AoICAQDuyaDrULBW0PLYMfDwG1cZ6qWlTCzhb+vffSNd6AvF/4uTwCpNNcbHH3WH 10 | st1FD1ZygGBFyWjb6QpGwW58JSd+6+UuvsVTzYSilhrd4afmNGyKg945e4z1vY91 11 | bzivNPQ+LcXPMFx+GLcncrYzyQLsK5fqNOuVQDXPhrFG3o4gDxhUWsHjpBKWvFwI 12 | n1VzNcP17/MML5pYAnOGnlNQpjqexbzSEsDF3b1mTi50kkfHD/NN4zSaJMJGvsFj 13 | aIFhakEuLA6GeI7OO+do3oh5U8osUYOznbB1BtC3NGAE9NU1JeSHQH3speUX8iH7 14 | 0UjNdhyf96HY/ZDMRJF4bfWLdBCxCAmWJEYADbciUxus6TUjrjEzKSceMEmjg2Or 15 | DMUISSmsH44Usx6S367WmGVpsuMh39X0GQRLz+ntwqJi1yvRttcdrhrNo7jOEG2R 16 | Elm113+GDo1mmtMB6TrKU42kEQsR1yH7FAO0/zsvnnVjUtFEHH45SQWS43fuZXO1 17 | ioS0SFNO/7wKZS+cYOzzGlMvv+eW6jVYouXupM/Fa5+vkhYnw6v/LTWIYylw9XbZ 18 | Xpgf+aSa8ZWiaTKfHhEHFmhVPjqUF4bkACVUknu+5UZKUTE1+69PgpEe0uhyzJ/z 19 | QIwZ6+MHpzDx2cfi6qU2sKGS8M99upjMm7GQ4LqHlG/lYrterwIDAQABo2MwYTAO 20 | BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQps8jE 21 | 36OH+GYFElj9Riq4mA15hzAdBgNVHQ4EFgQUKbPIxN+jh/hmBRJY/UYquJgNeYcw 22 | DQYJKoZIhvcNAQENBQADggIBAK+GzchsHQruy9sCZ2QDtF6kveZT5JVfpfJ7Aspw 23 | VR3+VrH50aiGlSid4va1EBHWxD1uw7t3FMYvlvU/KAk+TA5+0GSrJFalO5nYNma9 24 | dYcgiD8tBQdB3tOU27wTrSD0VXsolXnRYNerNyeo5TWzqcy5InfZAT95XtmTE9me 25 | l1cu4yYwdT1/+m0ws9YZLdvaDK9tIJzkOn4CFTCvMUcGMOg1ncE1X07LH26ibsiV 26 | zgbVBoK6Qe+O4w533pTta9rOoudOqL44F/+YPSSfBNvRD49OpQNYsf2umgS2WTsk 27 | wcSEM/gJoelE0Avp4c1rz0/6VQsX+JNOnHadKZQl1GUrUxEAiAy4A5hpz6qyTNtu 28 | DSc3tdbjaddLr7jESAaU3Zbi/s+vDeYqgO5jsR6RX1iyBpUTdciTnZOGSyRE5ek2 29 | g6IERpmnhP4bKL2ylJK+OchYFL/HFPFiAuRXBhiv5o8AOQGvWVY8bCvzliI869IS 30 | w4kdpmxnyx9GKxcuTTmvr3TMIbEpCuG+vCsmjvl+JtP/bGWSNjSpzxO4NEABnAjM 31 | BI4m+SGQy2wxJ3dEONZvjk1ph0bYE/cQRlgoxAlk8JuGt0XTw03Ar2EklhN8IeBk 32 | 8e6KDeKxSNX60z3XTChCgTPj+ErwdNzX8tcRo5FrQ68VwTF27+pYYAEfAs2hqHZ2 33 | KHW0 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /endesive/email/sign.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | import base64 3 | 4 | from cryptography import x509 5 | from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes 6 | 7 | from endesive import signer 8 | 9 | 10 | class SignedData(object): 11 | 12 | def email(self, hashalgo, datau, datas, prefix): 13 | s = b'''\ 14 | MIME-Version: 1.0 15 | Content-Type: multipart/signed; protocol="application/%spkcs7-signature"; micalg="%s"; boundary="----46F1AAD10BE922477643C0A33C40D389" 16 | 17 | This is an S/MIME signed message 18 | 19 | ------46F1AAD10BE922477643C0A33C40D389 20 | %s 21 | ------46F1AAD10BE922477643C0A33C40D389 22 | Content-Type: application/%spkcs7-signature; name="smime.p7s" 23 | Content-Transfer-Encoding: base64 24 | Content-Disposition: attachment; filename="smime.p7s" 25 | 26 | %s 27 | ------46F1AAD10BE922477643C0A33C40D389-- 28 | 29 | ''' % (prefix, hashalgo, datau, prefix, datas) 30 | return s 31 | 32 | def build(self, datau, key, cert, othercerts, hashalgo, attrs, pss=False): 33 | datau = datau.replace(b'\n', b'\r\n') 34 | datas = signer.sign(datau, key, cert, othercerts, hashalgo, attrs, pss=pss) 35 | datas = base64.encodebytes(datas) 36 | if hashalgo == 'sha1': 37 | hashalgo = b'sha1' 38 | elif hashalgo == 'sha256': 39 | hashalgo = b'sha-256' 40 | elif hashalgo == 'sha512': 41 | hashalgo = b'sha-512' 42 | prefix = [b'x-', b''][pss] 43 | data = self.email(hashalgo, datau, datas, prefix) 44 | return data 45 | 46 | 47 | def sign(datau:bytes, key: PrivateKeyTypes, cert: x509.Certificate, certs: list[x509.Certificate], hashalgo='sha1', attrs=True, pss=False)->bytes: 48 | """ 49 | Sign data with private key and encapsulate the result (data and signature) as S/MIME message. 50 | 51 | :param datau: Data to sign (bytes). 52 | :param key: Private key to sign with (PrivateKeyTypes). 53 | :param cert: Certificate to sign with (x509.Certificate). 54 | :param certs: List of additional certificates (list of x509.Certificate). 55 | :param hashalgo: Hash algorithm to use (str, default 'sha1'). 56 | :param attrs: Whether to include attributes (bool, default True). 57 | :param pss: Whether to use PSS padding (bool, default False). 58 | :return: Signed data as bytes. 59 | """ 60 | cls = SignedData() 61 | return cls.build(datau, key, cert, certs, hashalgo, attrs, pss) 62 | -------------------------------------------------------------------------------- /examples/signature_appearances/signature_appearance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 0, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | "auto_sigfield": True, 25 | #"sigandcertify": False, 26 | "signaturebox": (72, 396, 360, 468), 27 | "signform": False, 28 | "sigfield": "Signature", 29 | 30 | # Text will be in the default font 31 | # Fields in the list display will be included in the text listing 32 | # Icon and background can both be set to images by having their 33 | # value be a path to a file or a PIL Image object 34 | # If background is a list it is considered to be an opaque RGB colour 35 | # Outline is the colour used to draw both the border and the text 36 | "signature_appearance": { 37 | 'background': [0.75, 0.8, 0.95], 38 | 'icon': '../signature_test.png', 39 | 'outline': [0.2, 0.3, 0.5], 40 | 'border': 2, 41 | 'labels': True, 42 | 'display': 'CN,DN,date,contact,reason,location'.split(','), 43 | }, 44 | 45 | "contact": "mak@trisoft.com.pl", 46 | "location": "Szczecin", 47 | "signingdate": date, 48 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 49 | "password": "1234", 50 | } 51 | with open("../ca/demo2_user1.p12", "rb") as fp: 52 | p12 = pkcs12.load_key_and_certificates( 53 | fp.read(), b"1234", backends.default_backend() 54 | ) 55 | fname = "../pdf_forms/blank_form.pdf" 56 | if len(sys.argv) > 1: 57 | fname = sys.argv[1] 58 | datau = open(fname, "rb").read() 59 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 60 | fname = fname.replace(".pdf", "-signature_appearance.pdf") 61 | with open(fname, "wb") as fp: 62 | fp.write(datau) 63 | fp.write(datas) 64 | 65 | 66 | main() 67 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-ltv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | from cryptography import x509 8 | 9 | from endesive.pdf import cms 10 | 11 | 12 | def main(): 13 | date = datetime.datetime.now() 14 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 15 | dct = { 16 | "aligned": 16384, 17 | "sigflags": 3, 18 | "sigflagsft": 132, 19 | "sigpage": 0, 20 | # "sigbutton": True, 21 | # "sigfield": "Signature1", 22 | # "auto_sigfield": True, 23 | # "sigandcertify": True, 24 | # "signaturebox": (470, 840, 570, 640), 25 | "signature": "Dokument podpisany cyfrowo ąćęłńóśżź", 26 | # "signature_img": "signature_test.png", 27 | "contact": "contact:mak@trisoft.com.pl", 28 | "location": "Szczecin", 29 | "signingdate": date, 30 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 31 | "password": "1234", 32 | 'tsa_url': 'http://timestamp.digicert.com', 33 | "ltv": True, 34 | } 35 | with open("ca/demo2_user1.p12", "rb") as fp: 36 | p12 = pkcs12.load_key_and_certificates( 37 | fp.read(), b"1234", backends.default_backend() 38 | ) 39 | fname = "pdf.pdf" 40 | if len(sys.argv) > 2: 41 | fname = sys.argv[2] 42 | datau = open(fname, "rb").read() 43 | 44 | print(f"Signing certificate subject: {p12[1].subject.rfc4514_string()}") 45 | print(f"Signing certificate issuer: {p12[1].issuer.rfc4514_string()}") 46 | print(f"Additional certificates in chain: {len(p12[2]) if p12[2] else 0}") 47 | 48 | issuer_cert = None 49 | if p12[2]: 50 | issuer_cert = p12[2][0] 51 | print( 52 | f"Using issuer certificate: {issuer_cert.subject.rfc4514_string()}") 53 | else: 54 | print("No additional certificates found in P12 file") 55 | 56 | # ocsp_url = "http://ca.trisoft.com.pl/ocsp" 57 | 58 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256", 59 | # ocspurl=ocsp_url, 60 | ocspissuer=issuer_cert, 61 | timestampurl=dct['tsa_url']) 62 | fname = fname.replace(".pdf", "-signed-cms-ltv.pdf") 63 | with open(fname, "wb") as fp: 64 | fp.write(datau) 65 | fp.write(datas) 66 | 67 | 68 | main() 69 | -------------------------------------------------------------------------------- /examples/pdf-verify-hsm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # coding: utf-8 3 | 4 | import os 5 | import sys 6 | import sysconfig 7 | 8 | os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' 9 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): 10 | open('softhsm2.conf', 'wt').write('''\ 11 | log.level = DEBUG 12 | directories.tokendir = %s/softhsm2/ 13 | objectstore.backend = file 14 | slots.removable = false 15 | ''' % os.getcwd()) 16 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): 17 | os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) 18 | 19 | # 20 | #!/bin/bash 21 | #SOFTHSM2_CONF=softhsm2.conf 22 | #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 23 | #softhsm2-util --show-slots 24 | # 25 | 26 | if sys.platform == 'win32': 27 | dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' 28 | else: 29 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 30 | 31 | from endesive import hsm, pdf 32 | import PyKCS11 as PK11 33 | from asn1crypto import pem as asn1pem 34 | 35 | ''' 36 | Create two certificates: 37 | 1. self signed CA certificate with serial equal to HSM keyID=0x01 38 | 2. USER 1 certificate with serial equal to HSM keyID=0x666690 39 | ''' 40 | class HSM(hsm.HSM): 41 | def main(self): 42 | cakeyID = bytes((0x1,)) 43 | ca_cert_pem = asn1pem.armor('CERTIFICATE', self.cert_load(cakeyID)) 44 | trusted_cert_pems = [ca_cert_pem] 45 | for fname in ( 46 | 'pdf-signed-cms-hsm.pdf', 47 | 'pdf-signed-cms-hsm-signed-cms-hsm.pdf', 48 | "pdf-signed-cms-hsm-signature_appearance.pdf", 49 | "pdf-signed-cms-hsm-signature_manual.pdf", 50 | ): 51 | print('*' * 20, fname) 52 | try: 53 | data = open(fname, 'rb').read() 54 | except: 55 | print('skip') 56 | continue 57 | results = pdf.verify(data, trusted_cert_pems) 58 | for i in range(len(results)): 59 | print('*'*10, 'signature #{}'.format(i+1)) 60 | (hashok, signatureok, certok) = results[i] 61 | print('signature ok?', signatureok) 62 | print('hash ok?', hashok) 63 | print('cert ok?', certok) 64 | 65 | def main(): 66 | cls = HSM(dllpath) 67 | cls.login("endesieve", "secret1") 68 | try: 69 | cls.main() 70 | finally: 71 | cls.logout() 72 | main() 73 | -------------------------------------------------------------------------------- /examples/csmimersaca.cer.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGsjCCBJqgAwIBAgIQDOEyJ6gs5qPQ81fDbLYehjANBgkqhkiG9w0BAQ0FADB6 3 | MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu 4 | MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV 5 | BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMjMwODAxMDgwOTQ5WhcNMzgw 6 | NzIzMDgwOTQ5WjBOMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEg 7 | U3lzdGVtcyBTLkEuMRwwGgYDVQQDDBNDZXJ0dW0gU01JTUUgUlNBIENBMIICIjAN 8 | BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA07ncX0x76hCIVcAweGQwyavnwwat 9 | WvpwgQkxnZ499ukRpAkthNUOt6B08JQ/bZCbemvFA8CCGenhvPziJDPwPitpczKw 10 | XD/XRAXRmagl8G6quDuGfz5fKJuzuxuW8J2mnKRaSxk16LYOj0/0fVFlzFvktSOS 11 | oqKwV0TnhV9Dfgm68lHwkI9LweRfOWF6sh5GmXYDvGHS/o/qX1ETiRi3Zxn3+m9/ 12 | jufGwWen+CFFTgEYcmmi0MtaH58JFdADNlpfwCIwPCq8LUTodM+fxd5PElMjcryE 13 | GhtLz8nLR0Vi7Fxm5MB6N8DqV0uCpAEEdc0flCwxgjBYUUl/4/7JCcWJgLam1Pr+ 14 | esGHixDPS5n0wrDkq2PMjUYqdD0EuBa2covPPFguPYgS8zJLTviRLJgyIgGA5PZI 15 | w/VgIbm4fIjf+UXbnFc/ZbpHwmtPo2B+7EYaXNdh92zNrn7020SBOVtQkWgC4hs5 16 | RFs4QN1FiAW2vmOAa4bbca68ChvXzkQLm5xXtMgwp13BwuDfdGCMCeOLD9AYAvS4 17 | xkfj2TU870gI/qgpmesSTj1JbLJeh8nBD1OirFvSp5WZhE7HKnAvld6MwZPMTNFW 18 | fwB2d+KVyXHpn1huHuK8Xh9BUncFBM495EwPODqkcW2/wttV7IktV8k9ylCBpQ4i 19 | BEBYJw/U5PzxqRMCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O 20 | BBYEFGb7ww++9L/gnMmrTd5HGb3AyqZoMB8GA1UdIwQYMBaAFIz7HHW8AtOfTi5I 21 | 2flgVKrEs0/6MA4GA1UdDwEB/wQEAwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDBAYI 22 | KwYBBQUHAwIwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5jZXJ0dW0ucGwv 23 | Y3RyY2EuY3JsMGsGCCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1 24 | YmNhLm9jc3AtY2VydHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRv 25 | cnkuY2VydHVtLnBsL2N0cmNhLmNlcjA6BgNVHSAEMzAxMC8GBFUdIAAwJzAlBggr 26 | BgEFBQcCARYZaHR0cHM6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQ0F 27 | AAOCAgEAAnVohU6xF3o2wjYb5UBo5xq+BsAgUUXLNfrkLpknIpLSrnLI9Zgm97Zg 28 | dPWw8mtG3klA1Xnf4fn2zyhZTjdposEWGcHRl0hTa8p8xgtaGEBt0j0uqsF0tomX 29 | uJEOHdKU0Z7Rj3h0Xtd6OZ3d7ScP/l2p1KE0cu/zdjcUPAa9er/jGujdl6qi4/s1 30 | xjJ/IeXNC6Zqp5GjMZNoYi8VxDixaBl1zopd8BwpILZWYH24MnivwBo6hI/VzXww 31 | ntleH0y7GKpW/gGlQDKVxbXs3hi67CAHn/jGI1zaBimBnhzPAIjR3iMWr5OOTvRL 32 | b2nf5Srz3B9IYDK/cE0XgkZ5o6aHR4MXChtCyyOqy0eEWxH0X961fMckeipH4yMu 33 | 1vKTfwsf4vA/6wDOOmHEtvNXbs+N19DmsOlI4qhcImnvA3ir0yDSwUfsnyXUP5S7 34 | LDQBt0DcV0R6MzSVKf1HqlJ39VkAuDWm0FyqeeIVkwkgXnPp+edPkRIPz/rQ4vlL 35 | KBaohPTKc/yPyqQNxRsoaQ8WGy4sP3tJ2C6rdR6l/BeC+LC31t+OqxB7QVlTT5rE 36 | Ji4yOpn4ZvHOBV94350KMDwy76jRibDv3nN/e3sm/JzfvDEjNSlz1bDIeC70Wb41 37 | S9A1RHzhgX9vR1hF2LieZZYWPfzd9WsuBrL+tVYBRO7/YUIzOGQ= 38 | -----END CERTIFICATE----- 39 | -------------------------------------------------------------------------------- /examples/t-ocsp-get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import requests 4 | from cryptography import x509 5 | from cryptography.x509 import ocsp 6 | from cryptography.hazmat import backends 7 | from cryptography.hazmat.primitives import hashes, serialization 8 | from cryptography.hazmat.primitives.asymmetric import padding, utils 9 | from cryptography.hazmat.primitives.serialization import pkcs12 10 | 11 | def get_from_cert(cert, what): 12 | try: 13 | aia = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS) 14 | for access_description in aia.value: 15 | if access_description.access_method == what: 16 | return access_description.access_location.value 17 | except x509.ExtensionNotFound: 18 | return None 19 | return None 20 | 21 | def get_crl_from_cert(cert): 22 | try: 23 | cdp = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.CRL_DISTRIBUTION_POINTS) 24 | return cdp.value[0].full_name[0].value 25 | except x509.ExtensionNotFound: 26 | return None 27 | return None 28 | 29 | def main(): 30 | with open("ca/demo2_user1.p12", "rb") as fp: 31 | p12 = pkcs12.load_key_and_certificates( 32 | fp.read(), b"1234", backends.default_backend() 33 | ) 34 | 35 | ocspurl = 'http://ca.trisoft.com.pl/' 36 | 37 | ocspissuerurl = get_from_cert(p12[1], x509.OID_OCSP) 38 | rootcerturl = get_from_cert(p12[1], x509.OID_CA_ISSUERS) 39 | crlurl = get_crl_from_cert(p12[1]) 40 | 41 | print('crlurl', crlurl) 42 | response = requests.get(crlurl) 43 | with open('t-ocsp-crl.der', 'wb') as fp: 44 | fp.write(response.content) 45 | 46 | print('ocspissuerurl', ocspissuerurl) 47 | response = requests.get(ocspissuerurl) 48 | ocspissuer = response.content 49 | with open('t-ocsp-issuer.der', 'wb') as fp: 50 | fp.write(ocspissuer) 51 | 52 | ocspissuer = x509.load_der_x509_certificate(ocspissuer, backends.default_backend()) 53 | 54 | builder = ocsp.OCSPRequestBuilder() 55 | builder = builder.add_certificate(p12[1], ocspissuer, hashes.SHA1()) 56 | req = builder.build() 57 | data = req.public_bytes(serialization.Encoding.DER) 58 | 59 | open("t-ocsp-req.bin", "wb").write(data) 60 | response = requests.post( 61 | ocspurl, 62 | headers={"Content-Type": "application/ocsp-request"}, 63 | data=data, 64 | ) 65 | open("t-ocsp-resp.bin", "wb").write(response.content) 66 | 67 | 68 | main() 69 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/config/graphics_state.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | GraphicsState 4 | ~~~~~~~~~~~~~ 5 | Configuration for an annotation's graphics state. 6 | 7 | :copyright: Copyright 2019 Autodesk, Inc. 8 | :license: MIT, see LICENSE for details. 9 | """ 10 | import attr 11 | from ..pdfrw import PdfDict, PdfName 12 | 13 | from ..config.constants import ALLOWED_LINE_CAPS 14 | from ..config.constants import ALLOWED_LINE_JOINS 15 | from ..util.validation import between 16 | from ..util.validation import Enum 17 | from ..util.validation import Field 18 | from ..util.validation import Number 19 | from ..util.validation import positive 20 | from ..util.validation import validate_dash_array 21 | 22 | 23 | NAME_TO_PDF_ATTR = { 24 | "line_width": "LW", 25 | "line_cap": "LC", 26 | "line_join": "LJ", 27 | "miter_limit": "ML", 28 | "dash_array": "D", 29 | "stroke_transparency": "CA", 30 | "fill_transparency": "ca", 31 | } 32 | 33 | 34 | @attr.s 35 | class GraphicsState(object): 36 | """External graphics state config object, that can be used with explicit 37 | content streams to control annotation appearance. 38 | 39 | Some of these values can also be specified by their own operators in the 40 | content stream. For example, the line_width property can also be specified 41 | by the StrokeWidth (w) content stream operator. 42 | 43 | See the full PDF spec for constraints on and descriptions of these values. 44 | There are a lot more graphics state options, but they are highly technical 45 | and beyond the scope of this library. 46 | """ 47 | 48 | line_width = Number(default=None, validator=positive) 49 | line_cap = Enum(ALLOWED_LINE_CAPS, default=None) 50 | line_join = Enum(ALLOWED_LINE_JOINS, default=None) 51 | miter_limit = Number(default=None) 52 | dash_array = Field(list, validator=validate_dash_array, default=None) 53 | stroke_transparency = Number(default=None, validator=between(0, 1)) 54 | fill_transparency = Number(default=None, validator=between(0, 1)) 55 | 56 | def as_pdf_dict(self): 57 | pdf_dict = PdfDict(Type=PdfName("ExtGState")) 58 | for attr_name, attr_value in self.__dict__.items(): 59 | if attr_value is not None: 60 | pdf_name = NAME_TO_PDF_ATTR[attr_name] 61 | pdf_dict[PdfName(pdf_name)] = attr_value 62 | return pdf_dict 63 | 64 | def has_content(self): 65 | """Returns True if any of the attributes is non-null.""" 66 | return any(value is not None for value in self.__dict__.values()) 67 | -------------------------------------------------------------------------------- /examples/pdf-verify-rsa_sha1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import hashlib 4 | from endesive.pdf.PyPDF2 import PdfFileReader 5 | from cryptography import x509 6 | from cryptography.exceptions import InvalidSignature 7 | from cryptography.hazmat.backends import default_backend 8 | from cryptography.hazmat.primitives import hashes 9 | from cryptography.hazmat.primitives.asymmetric import padding 10 | 11 | 12 | def main(): 13 | fname = "pdf-adobe-webcapture-x509.rsa_sha1.pdf" 14 | pdf = PdfFileReader(fname) 15 | catalog = pdf.trailer["/Root"] 16 | docmdp = catalog["/Perms"]["/DocMDP"] 17 | if 0: 18 | print(catalog) 19 | for k, v in catalog.items(): 20 | print(k, "=", v) 21 | if 0: 22 | print(docmdp) 23 | for k, v in docmdp.items(): 24 | print(k, "=", v) 25 | dtype = docmdp["/Type"] 26 | dcert = docmdp["/Cert"] 27 | dbyterange = docmdp["/ByteRange"] 28 | dcontents = docmdp["/Contents"] 29 | dfilter = docmdp["/Filter"] 30 | dsubfilter = docmdp["/SubFilter"] 31 | dmethod = docmdp["/Reference"][0]["/DigestMethod"] 32 | 33 | try: 34 | dl = docmdp["/Reference"][0]["/DigestLocation"] 35 | dv = docmdp["/Reference"][0]["/DigestValue"] 36 | except: 37 | dl = [0, 0] 38 | dv = 'aa' 39 | assert dl[0] == 0 and dl[1] == 0 and dv == 'aa' 40 | 41 | print(dfilter, dsubfilter, dmethod, dbyterange) 42 | assert dfilter == '/Adobe.PPKLite' 43 | assert dsubfilter == '/adbe.x509.rsa_sha1' 44 | assert dmethod == '/MD5' 45 | del pdf 46 | 47 | data = open(fname, "rb").read() 48 | data1 = data[dbyterange[0] : dbyterange[1]] 49 | data2 = data[dbyterange[2] : dbyterange[2] + dbyterange[3]] 50 | if 1: 51 | data = data1 + data2 52 | else: 53 | # dirty games with dl and dv ? 54 | dig = hashlib.md5() 55 | dig.update(data1) 56 | if data2: 57 | dig.update(data2) 58 | data = dig.digest() 59 | if 0: 60 | open("a-cert.der", "wb").write(dcert) 61 | open("a-sig.der", "wb").write(signature) 62 | open("a-data-1.der", "wb").write(data1) 63 | open("a-data-2.der", "wb").write(data2) 64 | 65 | cert = x509.load_der_x509_certificate(dcert, default_backend()) 66 | signature = dcontents[3:] # ASN1 STRING 67 | pubkey = cert.public_key() 68 | try: 69 | pubkey.verify(signature, data, padding.PKCS1v15(), hashes.SHA1()) 70 | print('signature ok') 71 | except InvalidSignature: 72 | print('invalid signature') 73 | 74 | main() 75 | -------------------------------------------------------------------------------- /endesive/pdf/pdf.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | import hashlib 3 | 4 | from endesive import signer 5 | from . import fpdf 6 | 7 | 8 | class FPDF(fpdf.FPDF): 9 | signer = True 10 | 11 | def pkcs11_aligned(self, data): 12 | data = ''.join(['%02x' % i for i in data]) 13 | nb = 0x4000 - len(data) 14 | data = data + '0' * (0x4000 - len(data)) 15 | return data 16 | 17 | def pkcs11_setup(self, config, key, cert, othercerts, algomd): 18 | self.pkcs11config = config 19 | self.pkcs11zeros = self.pkcs11_aligned([0]) 20 | self.pkcs11annot = 0 21 | self.pkcs11key = key 22 | self.pkcs11cert = cert 23 | self.pkcs11certs = othercerts 24 | self.pkcs11algomd = algomd 25 | 26 | def pkcs11_signature(self): 27 | self._newobj() 28 | self.pkcs11annot = self.n 29 | self._out('<>/T(signature%d)/V %d 0 R>>' % ( 30 | self.pkcs11annot, self.pkcs11annot + 1)) 31 | self._out('endobj') 32 | 33 | self._newobj() 34 | self._out('<= 0: 11 | i += len(s) 12 | return i 13 | 14 | def readline(self, start): 15 | i1 = i0 = start 16 | while self.data[i1] not in b'\r\n': 17 | i1 += 1 18 | n = i1 19 | while self.data[n] in b'\r\n': 20 | n += 1 21 | return self.data[i0:i1].strip(), n 22 | 23 | def xref(self): 24 | xref = 0 25 | while True: 26 | xref = self.find(b'\nxref\n', xref) 27 | if xref < 0: 28 | break 29 | n = xref 30 | while True: 31 | line, n = self.readline(n) 32 | line = line.split() 33 | try: 34 | assert len(line) == 2 35 | off, cnt = int(line[0]), int(line[1]) 36 | except: 37 | break 38 | for i in range(cnt): 39 | line, n = self.readline(n) 40 | line = line.split() 41 | if line[-1] == b'n': 42 | offset = int(line[0]) 43 | line1 = self.readline(offset)[0].split() 44 | try: 45 | assert len(line1) == 3 and int(line1[0]) == off + i 46 | except: 47 | print('bad xref:', line, line1, 'off:', off+i, len(line1)) 48 | print(line1, off+i, offset) 49 | #self.xref.append( 50 | def byterange(self): 51 | start = self.find(b'/ByteRange') 52 | i0 = self.find(b'[', start) 53 | i1 = self.find(b']', start) 54 | line = self.data[i0:i1-1] 55 | line = line.split() 56 | br = [int(line[0]), int(line[1]), int(line[2]), int(line[3])] 57 | print(br, [hex(i) for i in br]) 58 | c = self.data[br[1]] 59 | print('[{:06x}]: {:d} {:02x}'.format(br[1], c, c)) 60 | c = self.data[br[2]] 61 | print('[{:06x}]: {:d} {:02x}'.format(br[2], c, c)) 62 | print(len(self.data), br[2]+br[3]) 63 | contents = self.data[br[0] + br[1] + 1 : br[2] - 1] 64 | print('[contents]:', len(contents)) 65 | 66 | def main(self): 67 | self.xref() 68 | self.byterange() 69 | 70 | for fname in ( 71 | #"pdf-certum.pdf", 72 | #"pdf-acrobat.pdf", 73 | 'pdf-signed-java.pdf', 74 | 'pdf-signed-pypdf.pdf', 75 | 'pdf-encrypted-signed-java.pdf', 76 | 'pdf-encrypted-signed-pypdf.pdf', 77 | ): 78 | print('*'*20, fname) 79 | try: 80 | cls = Main(fname) 81 | except IOError: 82 | continue 83 | cls.main() 84 | -------------------------------------------------------------------------------- /examples/signature_appearances/signature-existing-field.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 0, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | #"auto_sigfield": False, 25 | #"sigandcertify": False, 26 | #"signaturebox": (0, 0, 590, 155), 27 | "signform": True, 28 | "sigfield": "Signature", 29 | "signature_manual": [ 30 | # R G B 31 | ['fill_colour', 0.95, 0.95, 0.95], 32 | 33 | # *[bounding box] 34 | ['rect_fill', 0, 0, 270, 18], 35 | 36 | # R G B 37 | ['stroke_colour', 0.8, 0.8, 0.8], 38 | 39 | # key *[bounding box] 40 | ['image', 'sig0', 0, 0, 59, 15], 41 | 42 | # inset 43 | ['border', 2], 44 | 45 | # font fs 46 | ['font', 'default', 7], 47 | # R G B 48 | ['fill_colour', 0, 0, 0], 49 | 50 | # text 51 | ['text_box', 'signed using endesive\ndate: {}'.format(date), 52 | # font *[bounding box], fs, wrap, align, baseline 53 | 'default', 0, 2, 270, 18, 7, True, 'right', 'top'], 54 | ], 55 | # key: name used in image directives 56 | # value: PIL Image object or path to image file 57 | "manual_images": {'sig0': '../signature_test.png'}, 58 | # key: name used in font directives 59 | # value: path to TTF Font file 60 | "manual_fonts": {}, 61 | 62 | "contact": "mak@trisoft.com.pl", 63 | "location": "Szczecin", 64 | "signingdate": date, 65 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 66 | "password": "1234", 67 | } 68 | with open("../ca/demo2_user1.p12", "rb") as fp: 69 | p12 = pkcs12.load_key_and_certificates( 70 | fp.read(), b"1234", backends.default_backend() 71 | ) 72 | fname = "../pdf_forms/blank_form.pdf" 73 | if len(sys.argv) > 1: 74 | fname = sys.argv[1] 75 | datau = open(fname, "rb").read() 76 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 77 | fname = fname.replace(".pdf", "-signature-existing-field.pdf") 78 | with open(fname, "wb") as fp: 79 | fp.write(datau) 80 | fp.write(datas) 81 | 82 | 83 | main() 84 | -------------------------------------------------------------------------------- /examples/xml-make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import io 4 | 5 | 6 | def main(): 7 | io.open('xml.xml', 'wt', encoding='utf-8').write('''\ 8 | 9 | 13 | 14 | VAT-7 15 | 16 | 17 17 | 1 18 | 2017 19 | 2 20 | 3215 21 | 22 | 23 | 24 | 7791011327 25 | Nazwa firmy 26 | 630303023 27 | 28 | 29 | 30 | 0 31 | 3108 32 | 3108 33 | 0 34 | 0 35 | 998293 36 | 49915 37 | 901697 38 | 72135 39 | 3334214 40 | 766869 41 | 3177289 42 | 187401 43 | 44326 44 | 8864 45 | 0 46 | 0 47 | 0 48 | 0 49 | 66801 50 | 15364 51 | 0 52 | 0 53 | 0 54 | 0 55 | 0 56 | 0 57 | 0 58 | 0 59 | 0 60 | 8713129 61 | 913147 62 | 512089 63 | 54480 64 | 12531 65 | 8152972 66 | 1279013 67 | 0 68 | 0 69 | -138 70 | 1380 71 | 1804875 72 | 0 73 | 0 74 | 0 75 | 0 76 | 891728 77 | 0 78 | 0 79 | 0 80 | 0 81 | 891728 82 | 2 83 | 2 84 | 2 85 | 914842496 86 | 2017-05-09 87 | 88 | 1 89 | 90 | ''' 91 | ) 92 | 93 | 94 | main() 95 | -------------------------------------------------------------------------------- /examples/signature_appearances/signature_manual.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from cryptography.hazmat import backends 6 | from cryptography.hazmat.primitives.serialization import pkcs12 7 | 8 | from endesive.pdf import cms 9 | 10 | # from endesive.pdf import cmsn as cms 11 | 12 | # import logging 13 | # logging.basicConfig(level=logging.DEBUG) 14 | 15 | 16 | def main(): 17 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 18 | date = date.strftime("D:%Y%m%d%H%M%S+00'00'") 19 | dct = { 20 | "aligned": 0, 21 | "sigflags": 3, 22 | "sigflagsft": 132, 23 | "sigpage": 0, 24 | #"auto_sigfield": False, 25 | #"sigandcertify": False, 26 | #"signaturebox": (0, 0, 590, 155), 27 | "signform": True, 28 | "sigfield": "Signature", 29 | "signature_manual": [ 30 | # R G B 31 | ['fill_colour', 0.95, 0.95, 0.95], 32 | 33 | # *[bounding box] 34 | ['rect_fill', 0, 0, 270, 18], 35 | 36 | # R G B 37 | ['stroke_colour', 0.8, 0.8, 0.8], 38 | 39 | # inset 40 | ['border', 2], 41 | 42 | # key *[bounding box] distort centred 43 | ['image', 'sig0', 0, 0, 270, 18, False, False], 44 | 45 | # font fs 46 | ['font', 'default', 7], 47 | # R G B 48 | ['fill_colour', 0, 0, 0], 49 | 50 | # text 51 | ['text_box', 'signed using endesive\ndate: {}'.format(date), 52 | # font *[bounding box], fs, wrap, align, baseline 53 | 'default', 0, 2, 270, 18, 7, True, 'right', 'top'], 54 | ], 55 | # key: name used in image directives 56 | # value: PIL Image object or path to image file 57 | "manual_images": {'sig0': '../signature_test.png'}, 58 | # key: name used in font directives 59 | # value: path to TTF Font file 60 | "manual_fonts": {}, 61 | 62 | "contact": "mak@trisoft.com.pl", 63 | "location": "Szczecin", 64 | "signingdate": date, 65 | "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", 66 | "password": "1234", 67 | } 68 | with open("../ca/demo2_user1.p12", "rb") as fp: 69 | p12 = pkcs12.load_key_and_certificates( 70 | fp.read(), b"1234", backends.default_backend() 71 | ) 72 | fname = "../pdf_forms/blank_form.pdf" 73 | if len(sys.argv) > 1: 74 | fname = sys.argv[1] 75 | datau = open(fname, "rb").read() 76 | datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") 77 | fname = fname.replace(".pdf", "-signature_manual.pdf") 78 | with open(fname, "wb") as fp: 79 | fp.write(datau) 80 | fp.write(datas) 81 | 82 | 83 | main() 84 | -------------------------------------------------------------------------------- /examples/xml-hsm-softhsm2-enveloped.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from lxml import etree 4 | from cryptography import x509 5 | from cryptography.hazmat.backends import default_backend 6 | from cryptography.hazmat.primitives import serialization 7 | 8 | from endesive import xades, signer, hsm 9 | 10 | import os 11 | import sys 12 | import sysconfig 13 | 14 | os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" 15 | if sys.platform == "win32": 16 | dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" 17 | else: 18 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 19 | 20 | import PyKCS11 as PK11 21 | 22 | 23 | class Signer(hsm.HSM): 24 | def certificate(self): 25 | self.login("endesieve", "secret1") 26 | keyid = bytes((0x66, 0x66, 0x90)) 27 | try: 28 | pk11objects = self.session.findObjects( 29 | [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] 30 | ) 31 | all_attributes = [ 32 | # PK11.CKA_SUBJECT, 33 | PK11.CKA_VALUE, 34 | # PK11.CKA_ISSUER, 35 | # PK11.CKA_CERTIFICATE_CATEGORY, 36 | # PK11.CKA_END_DATE, 37 | PK11.CKA_ID, 38 | ] 39 | 40 | for pk11object in pk11objects: 41 | try: 42 | attributes = self.session.getAttributeValue( 43 | pk11object, all_attributes 44 | ) 45 | except PK11.PyKCS11Error as e: 46 | continue 47 | 48 | attrDict = dict(list(zip(all_attributes, attributes))) 49 | cert = bytes(attrDict[PK11.CKA_VALUE]) 50 | if keyid == bytes(attrDict[PK11.CKA_ID]): 51 | return keyid, cert 52 | finally: 53 | self.logout() 54 | return None, None 55 | 56 | def sign(self, keyid, data, mech): 57 | self.login("endesieve", "secret1") 58 | try: 59 | privKey = self.session.findObjects( 60 | [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] 61 | )[0] 62 | mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) 63 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 64 | return bytes(sig) 65 | finally: 66 | self.logout() 67 | 68 | 69 | def main(): 70 | clshsm = Signer(dllpath) 71 | keyid, cert = clshsm.certificate() 72 | 73 | def signproc(tosign, algosig): 74 | return clshsm.sign(keyid, tosign, algosig) 75 | 76 | data = open("xml.xml", "rb").read() 77 | 78 | cert = x509.load_der_x509_certificate(cert, backend=default_backend()) 79 | certcontent = cert.public_bytes(serialization.Encoding.DER) 80 | 81 | cls = xades.BES() 82 | doc = cls.enveloped(data, cert, certcontent, signproc, None, None) 83 | 84 | data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) 85 | open("xml-hsm-softhsm2-enveloped.xml", "wb").write(data) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /examples/xml-hsm-softhsm2-enveloping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from lxml import etree 4 | from cryptography import x509 5 | from cryptography.hazmat.backends import default_backend 6 | from cryptography.hazmat.primitives import serialization 7 | 8 | from endesive import xades, signer, hsm 9 | 10 | import os 11 | import sys 12 | import sysconfig 13 | 14 | os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" 15 | if sys.platform == "win32": 16 | dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" 17 | else: 18 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 19 | 20 | import PyKCS11 as PK11 21 | 22 | 23 | class Signer(hsm.HSM): 24 | def certificate(self): 25 | self.login("endesieve", "secret1") 26 | keyid = bytes((0x66, 0x66, 0x90)) 27 | try: 28 | pk11objects = self.session.findObjects( 29 | [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] 30 | ) 31 | all_attributes = [ 32 | # PK11.CKA_SUBJECT, 33 | PK11.CKA_VALUE, 34 | # PK11.CKA_ISSUER, 35 | # PK11.CKA_CERTIFICATE_CATEGORY, 36 | # PK11.CKA_END_DATE, 37 | PK11.CKA_ID, 38 | ] 39 | 40 | for pk11object in pk11objects: 41 | try: 42 | attributes = self.session.getAttributeValue( 43 | pk11object, all_attributes 44 | ) 45 | except PK11.PyKCS11Error as e: 46 | continue 47 | 48 | attrDict = dict(list(zip(all_attributes, attributes))) 49 | cert = bytes(attrDict[PK11.CKA_VALUE]) 50 | if keyid == bytes(attrDict[PK11.CKA_ID]): 51 | return keyid, cert 52 | finally: 53 | self.logout() 54 | return None, None 55 | 56 | def sign(self, keyid, data, mech): 57 | self.login("endesieve", "secret1") 58 | try: 59 | privKey = self.session.findObjects( 60 | [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] 61 | )[0] 62 | mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) 63 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 64 | return bytes(sig) 65 | finally: 66 | self.logout() 67 | 68 | 69 | def main(): 70 | clshsm = Signer(dllpath) 71 | keyid, cert = clshsm.certificate() 72 | 73 | def signproc(tosign, algosig): 74 | return clshsm.sign(keyid, tosign, algosig) 75 | 76 | data = open("xml.xml", "rb").read() 77 | cert = x509.load_der_x509_certificate(cert, backend=default_backend()) 78 | certcontent = cert.public_bytes(serialization.Encoding.DER) 79 | 80 | cls = xades.BES() 81 | doc = cls.enveloping( 82 | "dokument.xml", 83 | data, 84 | "application/xml", 85 | cert, 86 | certcontent, 87 | signproc, 88 | False, 89 | True, 90 | ) 91 | data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) 92 | 93 | open("xml-hsm-softhsm2-enveloping.xml", "wb").write(data) 94 | 95 | 96 | if __name__ == "__main__": 97 | main() 98 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hsm-certum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from certum import dllpath 6 | from cryptography import x509 7 | from cryptography.hazmat import backends 8 | import PyKCS11 as PK11 9 | from endesive import pdf, hsm 10 | 11 | 12 | class Signer(hsm.HSM): 13 | def certificate(self): 14 | self.login("profil bezpieczny", "9593") 15 | keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde] 16 | #keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] 17 | keyid = bytes(keyid) 18 | try: 19 | pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) 20 | all_attributes = [ 21 | #PK11.CKA_SUBJECT, 22 | PK11.CKA_VALUE, 23 | #PK11.CKA_ISSUER, 24 | #PK11.CKA_CERTIFICATE_CATEGORY, 25 | #PK11.CKA_END_DATE, 26 | PK11.CKA_ID, 27 | ] 28 | 29 | for pk11object in pk11objects: 30 | try: 31 | attributes = self.session.getAttributeValue(pk11object, all_attributes) 32 | except PK11.PyKCS11Error as e: 33 | continue 34 | 35 | attrDict = dict(list(zip(all_attributes, attributes))) 36 | cert = bytes(attrDict[PK11.CKA_VALUE]) 37 | if keyid == bytes(attrDict[PK11.CKA_ID]): 38 | return keyid, cert 39 | finally: 40 | self.logout() 41 | return None, None 42 | 43 | def sign(self, keyid, data, mech): 44 | self.login("profil bezpieczny", "9593") 45 | try: 46 | privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] 47 | mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) 48 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 49 | return bytes(sig) 50 | finally: 51 | self.logout() 52 | 53 | def main(): 54 | tspurl = "http://time.certum.pl" 55 | tspurl = "http://public-qlts.certum.pl/qts-17" 56 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 57 | date = date.strftime('%Y%m%d%H%M%S+00\'00\'') 58 | dct = { 59 | 'sigflags': 3, 60 | 'sigpage': 0, 61 | 'sigbutton': True, 62 | 'contact': 'mak@trisoft.com.pl', 63 | 'location': 'Szczecin', 64 | 'signingdate': date.encode(), 65 | 'reason': 'Dokument podpisany cyfrowo', 66 | 'signature': 'Dokument podpisany cyfrowo', 67 | 'signaturebox': (0, 0, 100, 100), 68 | } 69 | 70 | ocspurl = 'https://ocsp.certum.pl/' 71 | ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() 72 | ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) 73 | 74 | clshsm = Signer(dllpath) 75 | fname = 'pdf.pdf' 76 | if len (sys.argv) > 1: 77 | fname = sys.argv[1] 78 | datau = open(fname, 'rb').read() 79 | datas = pdf.cms.sign(datau, dct, 80 | None, None, 81 | [], 82 | 'sha256', 83 | clshsm, 84 | tspurl, 85 | ocspurl=ocspurl, 86 | ocspissuer=ocspissuer 87 | ) 88 | fname = fname.replace('.pdf', '-signed-cms-hsm-certum.pdf') 89 | with open(fname, 'wb') as fp: 90 | fp.write(datau) 91 | fp.write(datas) 92 | 93 | 94 | main() 95 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hsm-kir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | from kir import dllpath 6 | from cryptography import x509 7 | from cryptography.hazmat import backends 8 | import PyKCS11 as PK11 9 | from endesive import pdf, hsm 10 | 11 | 12 | class Signer(hsm.HSM): 13 | def certificate(self): 14 | self.login("profil bezpieczny", "232212") 15 | keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde] 16 | #keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] 17 | keyid = bytes(keyid) 18 | try: 19 | pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) 20 | all_attributes = [ 21 | #PK11.CKA_SUBJECT, 22 | PK11.CKA_VALUE, 23 | #PK11.CKA_ISSUER, 24 | #PK11.CKA_CERTIFICATE_CATEGORY, 25 | #PK11.CKA_END_DATE, 26 | PK11.CKA_ID, 27 | ] 28 | 29 | for pk11object in pk11objects: 30 | try: 31 | attributes = self.session.getAttributeValue(pk11object, all_attributes) 32 | except PK11.PyKCS11Error as e: 33 | continue 34 | 35 | attrDict = dict(list(zip(all_attributes, attributes))) 36 | cert = bytes(attrDict[PK11.CKA_VALUE]) 37 | if keyid == bytes(attrDict[PK11.CKA_ID]): 38 | return keyid, cert 39 | finally: 40 | self.logout() 41 | return None, None 42 | 43 | def sign(self, keyid, data, mech): 44 | self.login("profil bezpieczny", "9593") 45 | try: 46 | privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] 47 | mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) 48 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 49 | return bytes(sig) 50 | finally: 51 | self.logout() 52 | 53 | def main(): 54 | tspurl = "http://time.certum.pl" 55 | tspurl = "http://public-qlts.certum.pl/qts-17" 56 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 57 | date = date.strftime('%Y%m%d%H%M%S+00\'00\'') 58 | dct = { 59 | 'sigflags': 3, 60 | 'sigpage': 0, 61 | 'sigbutton': True, 62 | 'contact': 'mak@trisoft.com.pl', 63 | 'location': 'Szczecin', 64 | 'signingdate': date.encode(), 65 | 'reason': 'Dokument podpisany cyfrowo', 66 | 'signature': 'Dokument podpisany cyfrowo', 67 | 'signaturebox': (0, 0, 100, 100), 68 | } 69 | 70 | ocspurl = 'https://ocsp.certum.pl/' 71 | ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() 72 | ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) 73 | 74 | clshsm = Signer(dllpath) 75 | fname = 'pdf.pdf' 76 | if len (sys.argv) > 1: 77 | fname = sys.argv[1] 78 | datau = open(fname, 'rb').read() 79 | datas = pdf.cms.sign(datau, dct, 80 | None, None, 81 | [], 82 | 'sha256', 83 | clshsm, 84 | tspurl, 85 | ocspurl=ocspurl, 86 | ocspissuer=ocspissuer 87 | ) 88 | fname = fname.replace('.pdf', '-signed-cms-hsm-certum.pdf') 89 | with open(fname, 'wb') as fp: 90 | fp.write(datau) 91 | fp.write(datas) 92 | 93 | 94 | main() 95 | -------------------------------------------------------------------------------- /examples/t-rsa-sha256.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RSA-SHA-256: RSA signature condition using SHA-256. 3 | 4 | This RSA condition uses RSA-PSS padding with SHA-256. 5 | The salt length is set equal the digest length of 32 bytes. 6 | 7 | The public exponent is fixed at 65537 and the public 8 | modulus must be between 128 (1017 bits) and 9 | 512 bytes (4096 bits) long. 10 | 11 | RSA-SHA-256 is assigned the type ID 3. It relies on 12 | the SHA-256 and RSA-PSS feature suites which corresponds 13 | to a feature bitmask of 0x11. 14 | 15 | parameters = sigalgo["parameters"] 16 | salgo = parameters["hash_algorithm"].native["algorithm"].upper() 17 | mgf = getattr( 18 | padding, parameters["mask_gen_algorithm"].native["algorithm"].upper() 19 | )(getattr(hashes, salgo)()) 20 | salt_length = parameters["salt_length"].native 21 | try: 22 | public_key.verify( 23 | signature, 24 | signedData, 25 | padding.PSS(mgf, salt_length), 26 | getattr(hashes, salgo)(), 27 | ) 28 | signatureok = True 29 | except: 30 | signatureok = False 31 | ''' 32 | from cryptography.hazmat.backends import default_backend 33 | from cryptography.hazmat.primitives import hashes 34 | from cryptography.hazmat.primitives.asymmetric import padding, rsa 35 | 36 | def encrypt(message, public_key): 37 | # Hash the message 38 | digest = hashes.Hash(hashes.SHA256()) 39 | digest.update(message) 40 | hash_digest = digest.finalize() 41 | 42 | # Encrypt the hash with the public key 43 | encrypted = public_key.encrypt( 44 | hash_digest, 45 | padding.OAEP( 46 | mgf=padding.MGF1(algorithm=hashes.SHA256()), 47 | algorithm=hashes.SHA256(), 48 | label=None 49 | ) 50 | ) 51 | return encrypted 52 | 53 | def decrypt(encrypted, private_key): 54 | # Decrypt the encrypted hash 55 | decrypted = private_key.decrypt( 56 | encrypted, 57 | padding.OAEP( 58 | mgf=padding.MGF1(algorithm=hashes.SHA256()), 59 | algorithm=hashes.SHA256(), 60 | label=None 61 | ) 62 | ) 63 | return decrypted 64 | 65 | def main(): 66 | private_key = rsa.generate_private_key( 67 | public_exponent=65537, key_size=2048, backend=default_backend() 68 | ) 69 | public_key = private_key.public_key() 70 | 71 | # Data to encrypt 72 | message = b"Hello, world!" 73 | 74 | if 0: 75 | encrypted = encrypt(message, public_key) 76 | decrypted = decrypt(encrypted, private_key) 77 | digest = hashes.Hash(hashes.SHA256()) 78 | digest.update(message) 79 | hash_digest = digest.finalize() 80 | print('ok?', hash_digest == decrypted) 81 | 82 | 83 | salt_length = 32 # length(hash_digest) 84 | signature = private_key.sign( 85 | message, 86 | padding.PSS( 87 | mgf=padding.MGF1(algorithm=hashes.SHA256()), 88 | salt_length=salt_length, 89 | ), 90 | algorithm=hashes.SHA256(), 91 | ) 92 | try: 93 | public_key.verify( 94 | signature, 95 | message, 96 | padding.PSS( 97 | mgf=padding.MGF1(algorithm=hashes.SHA256()), 98 | salt_length=salt_length 99 | ), 100 | algorithm=hashes.SHA256(), 101 | ) 102 | ok = True 103 | except: 104 | ok = False 105 | print('ok=', ok) 106 | 107 | main() 108 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hash-sign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import base64 5 | import json 6 | from asn1crypto import pem as asn1pem 7 | from endesive import hsm 8 | 9 | import os 10 | import sysconfig 11 | 12 | os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" 13 | if not os.path.exists(os.path.join(os.getcwd(), "softhsm2.conf")): 14 | open("softhsm2.conf", "wt").write( 15 | """\ 16 | log.level = DEBUG 17 | directories.tokendir = %s/softhsm2/ 18 | objectstore.backend = file 19 | slots.removable = false 20 | """ 21 | % os.getcwd() 22 | ) 23 | if not os.path.exists(os.path.join(os.getcwd(), "softhsm2")): 24 | os.mkdir(os.path.join(os.getcwd(), "softhsm2")) 25 | 26 | # 27 | #!/bin/bash 28 | # SOFTHSM2_CONF=softhsm2.conf 29 | # softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 30 | # softhsm2-util --show-slots 31 | # 32 | 33 | if sys.platform == "win32": 34 | dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" 35 | else: 36 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 37 | 38 | import PyKCS11 as PK11 39 | 40 | 41 | class Signer(hsm.HSM): 42 | def certificate(self): 43 | self.login("endesieve", "secret1") 44 | keyid = bytes((0x66, 0x66, 0x90)) 45 | try: 46 | pk11objects = self.session.findObjects( 47 | [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] 48 | ) 49 | all_attributes = [ 50 | # PK11.CKA_SUBJECT, 51 | PK11.CKA_VALUE, 52 | # PK11.CKA_ISSUER, 53 | # PK11.CKA_CERTIFICATE_CATEGORY, 54 | # PK11.CKA_END_DATE, 55 | PK11.CKA_ID, 56 | ] 57 | 58 | for pk11object in pk11objects: 59 | try: 60 | attributes = self.session.getAttributeValue( 61 | pk11object, all_attributes 62 | ) 63 | except PK11.PyKCS11Error as e: 64 | continue 65 | 66 | attrDict = dict(list(zip(all_attributes, attributes))) 67 | cert = bytes(attrDict[PK11.CKA_VALUE]) 68 | if keyid == bytes(attrDict[PK11.CKA_ID]): 69 | return keyid, cert 70 | finally: 71 | self.logout() 72 | return None, None 73 | 74 | def sign(self, keyid, data, mech): 75 | self.login("endesieve", "secret1") 76 | try: 77 | privKey = self.session.findObjects( 78 | [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] 79 | )[0] 80 | mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) 81 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 82 | return bytes(sig) 83 | finally: 84 | self.logout() 85 | 86 | 87 | def main(): 88 | pdfname = 'pdf.pdf' 89 | if len (sys.argv) > 1: 90 | pdfname = sys.argv[1] 91 | config = open(pdfname + ".json", "rt").read() 92 | config = json.loads(config) 93 | 94 | tosign = base64.decodebytes(config['tosign'].encode('ascii')) 95 | 96 | clshsm = Signer(dllpath) 97 | keyid, cert = clshsm.certificate() 98 | signed_bytes = clshsm.sign(keyid, tosign, "sha256") 99 | 100 | config['signed_bytes'] = b"".join(base64.encodebytes(signed_bytes).split()).decode('ascii') 101 | config['certificate'] = asn1pem.armor("CERTIFICATE", cert).decode('ascii') 102 | json.dump(config, open(pdfname + ".json", "wt"), indent=4) 103 | 104 | 105 | main() 106 | -------------------------------------------------------------------------------- /examples/cert-info-hsm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | from endesive import pdf, hsm 5 | 6 | import os 7 | import sysconfig 8 | 9 | os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' 10 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): 11 | open('softhsm2.conf', 'wt').write('''\ 12 | log.level = DEBUG 13 | directories.tokendir = %s/softhsm2/ 14 | objectstore.backend = file 15 | slots.removable = false 16 | ''' % os.getcwd()) 17 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): 18 | os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) 19 | 20 | # 21 | #!/bin/bash 22 | #SOFTHSM2_CONF=softhsm2.conf 23 | #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 24 | #softhsm2-util --show-slots 25 | # 26 | 27 | if sys.platform == 'win32': 28 | dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' 29 | else: 30 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 31 | 32 | import PyKCS11 as PK11 33 | 34 | class Signer(hsm.HSM): 35 | def certificate(self): 36 | self.login("endesieve", "secret1") 37 | keyid = bytes((0x66,0x66,0x90)) 38 | try: 39 | pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) 40 | all_attributes = [ 41 | #PK11.CKA_SUBJECT, 42 | PK11.CKA_VALUE, 43 | #PK11.CKA_ISSUER, 44 | #PK11.CKA_CERTIFICATE_CATEGORY, 45 | #PK11.CKA_END_DATE, 46 | PK11.CKA_ID, 47 | ] 48 | 49 | for pk11object in pk11objects: 50 | try: 51 | attributes = self.session.getAttributeValue(pk11object, all_attributes) 52 | except PK11.PyKCS11Error as e: 53 | continue 54 | 55 | attrDict = dict(list(zip(all_attributes, attributes))) 56 | cert = bytes(attrDict[PK11.CKA_VALUE]) 57 | if keyid == bytes(attrDict[PK11.CKA_ID]): 58 | return keyid, cert 59 | finally: 60 | self.logout() 61 | return None, None 62 | 63 | def sign(self, keyid, data, mech): 64 | self.login("endesieve", "secret1") 65 | try: 66 | privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] 67 | mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) 68 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 69 | return bytes(sig) 70 | finally: 71 | self.logout() 72 | 73 | import binascii 74 | from cryptography.hazmat import backends 75 | from cryptography.hazmat.primitives import hashes, serialization 76 | from cryptography.hazmat.primitives.asymmetric import padding 77 | from cryptography.hazmat.primitives.serialization import pkcs12 78 | from asn1crypto import x509, pem 79 | 80 | 81 | def cert2asn(cert, cert_bytes=True): 82 | if isinstance(cert, x509.Certificate): 83 | return cert 84 | if cert_bytes: 85 | cert_bytes = cert.public_bytes(serialization.Encoding.PEM) 86 | else: 87 | cert_bytes = cert 88 | if pem.detect(cert_bytes): 89 | _, _, cert_bytes = pem.unarmor(cert_bytes) 90 | return x509.Certificate.load(cert_bytes) 91 | 92 | def main(): 93 | hsm = Signer(dllpath) 94 | hsm.login("endesieve", "secret1") 95 | keyid = bytes((0x66,0x66,0x90)) 96 | ic = hsm.cert_load(keyid) 97 | hsm.logout() 98 | print(ic) 99 | ic = cert2asn(ic, False) 100 | print(ic) 101 | main() 102 | -------------------------------------------------------------------------------- /examples/xml-hsm-certum-enveloped.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from certum import dllpath 4 | import PyKCS11 as PK11 5 | from lxml import etree 6 | from cryptography import x509 7 | from cryptography.hazmat.backends import default_backend 8 | from cryptography.hazmat.primitives import serialization 9 | 10 | from endesive import xades, signer, hsm 11 | 12 | 13 | class Signer(hsm.HSM): 14 | def certificate(self): 15 | self.login("profil bezpieczny", "9593") 16 | keyid = [ 17 | 0x5E, 18 | 0x9A, 19 | 0x33, 20 | 0x44, 21 | 0x8B, 22 | 0xC3, 23 | 0xA1, 24 | 0x35, 25 | 0x33, 26 | 0xC7, 27 | 0xC2, 28 | 0x02, 29 | 0xF6, 30 | 0x9B, 31 | 0xDE, 32 | 0x55, 33 | 0xFE, 34 | 0x83, 35 | 0x7B, 36 | 0xDE, 37 | ] 38 | # keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] 39 | keyid = bytes(keyid) 40 | try: 41 | pk11objects = self.session.findObjects( 42 | [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] 43 | ) 44 | all_attributes = [ 45 | # PK11.CKA_SUBJECT, 46 | PK11.CKA_VALUE, 47 | # PK11.CKA_ISSUER, 48 | # PK11.CKA_CERTIFICATE_CATEGORY, 49 | # PK11.CKA_END_DATE, 50 | PK11.CKA_ID, 51 | ] 52 | 53 | for pk11object in pk11objects: 54 | try: 55 | attributes = self.session.getAttributeValue( 56 | pk11object, all_attributes 57 | ) 58 | except PK11.PyKCS11Error as e: 59 | continue 60 | 61 | attrDict = dict(list(zip(all_attributes, attributes))) 62 | cert = bytes(attrDict[PK11.CKA_VALUE]) 63 | if keyid == bytes(attrDict[PK11.CKA_ID]): 64 | return keyid, cert 65 | finally: 66 | self.logout() 67 | return None, None 68 | 69 | def sign(self, keyid, data, mech): 70 | self.login("profil bezpieczny", "9593") 71 | try: 72 | privKey = self.session.findObjects( 73 | [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] 74 | )[0] 75 | mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) 76 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 77 | return bytes(sig) 78 | finally: 79 | self.logout() 80 | 81 | 82 | def main(): 83 | clshsm = Signer(dllpath) 84 | keyid, cert = clshsm.certificate() 85 | 86 | def signproc(tosign, algosig): 87 | return clshsm.sign(keyid, tosign, algosig) 88 | 89 | data = open("xml.xml", "rb").read() 90 | cert = x509.load_der_x509_certificate(cert, backend=default_backend()) 91 | certcontent = cert.public_bytes(serialization.Encoding.DER) 92 | 93 | for tspurl, tspcred in ( 94 | (None, None), 95 | ("http://public-qlts.certum.pl/qts-17", None) 96 | ): 97 | cls = xades.BES() 98 | doc = cls.enveloped(data, cert, certcontent, signproc, tspurl, tspcred) 99 | 100 | data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) 101 | if tspurl is not None: 102 | open("xml-hsm-certum-enveloped-t.xml", "wb").write(data) 103 | else: 104 | open("xml-hsm-certum-enveloped.xml", "wb").write(data) 105 | 106 | 107 | if __name__ == "__main__": 108 | main() 109 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/config/metadata.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Metadata 4 | ~~~~~~~~ 5 | Configuration for an annotation's metadata. 6 | 7 | :copyright: Copyright 2019 Autodesk, Inc. 8 | :license: MIT, see LICENSE for details. 9 | """ 10 | from datetime import datetime 11 | from datetime import timedelta 12 | from datetime import tzinfo 13 | from uuid import uuid4 14 | 15 | 16 | UNSET = object() 17 | 18 | 19 | class UTC(tzinfo): 20 | def utcoffset(self, dt): 21 | return timedelta(0) 22 | 23 | def dst(self, dt): 24 | return timedelta(0) 25 | 26 | def tzname(self, dt): 27 | return 'UTC' 28 | 29 | 30 | class Flags(object): 31 | Invisible = 1 32 | Hidden = 2 33 | Print = 4 34 | NoZoom = 8 35 | NoRotate = 16 36 | NoView = 32 37 | ReadOnly = 64 38 | Locked = 128 39 | ToggleNoView = 256 40 | LockedContents = 512 41 | 42 | 43 | class Metadata(object): 44 | """PDF annotation metadata class. 45 | 46 | By default, new annotations get the following properties: 47 | * CreationDate - defaults to UTC now 48 | * M (modified date) - defaults to UTC now 49 | * NM (unique name) - defaults to uuid4() 50 | * F (flags) - defaults to 4, just Flags.Print 51 | 52 | Datetime objects should be timezone-aware. If they're not, UTC is used. 53 | 54 | To leave any of these entries off the created annotation, pass kwarg=UNSET. 55 | 56 | Any additional kwargs will be set on the annotation object as /Name value. 57 | So for instance if you use Metadata(Subj='hi'), the annotation object in 58 | the PDF will have an attribute of `/Subj (hi)`. Acceptable value types are 59 | str, int, float, datetime, and lists of str/int/float. Other values may 60 | work, but may appear oddly formatted in the PDF, or break it entirely. 61 | """ 62 | 63 | def __init__( 64 | self, 65 | creation_date=None, 66 | modified_date=None, 67 | name=None, 68 | flags=None, 69 | **kwargs 70 | ): 71 | """ 72 | :param datetime|None|UNSET creation_date: 73 | :param datetime|None|UNSET modified_date: 74 | :param str|None|UNSET name: 75 | :param int|None|UNSET flags: if specified, a bunch of bitwise or-ed 76 | `Flags` values. For instance, to specify both Hidden and Invisible, 77 | use `Flags.Invisible | Flags.Hidden`. If flags are specified, the 78 | default `Print` flag is no longer set; it must be set explicity. 79 | """ 80 | self.metadata = {} 81 | self.set('CreationDate', creation_date, self.now) 82 | self.set('M', modified_date, self.now) 83 | self.set('NM', name, lambda: str(uuid4())) 84 | self.set('F', flags, lambda: Flags.Print) 85 | 86 | for k, v in kwargs.items(): 87 | if v is None: 88 | raise ValueError("Can't write Nones to PDF") 89 | self.set(k, v, None) 90 | 91 | def set(self, attr, value, default_func): 92 | if value is UNSET: 93 | return 94 | self.metadata[attr] = default_func() if value is None else value 95 | 96 | def iter(self): 97 | for name, value in self.metadata.items(): 98 | yield name, value 99 | 100 | @staticmethod 101 | def now(): 102 | return datetime.utcnow().replace(tzinfo=UTC()) 103 | 104 | 105 | def serialize_value(value): 106 | if isinstance(value, datetime): 107 | return serialize_datetime(value) 108 | return value 109 | 110 | 111 | def serialize_datetime(d): 112 | if d.tzinfo is None: 113 | d = d.replace(tzinfo=UTC()) 114 | offset_str = d.strftime('%z') 115 | offset_str = "{}'{}".format(offset_str[:3], offset_str[3:]) 116 | return d.strftime('D:%Y%m%d%H%M%S{}'.format(offset_str)) 117 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | import datetime 5 | import base64 6 | import json 7 | import hashlib 8 | from asn1crypto import cms, core, util 9 | from endesive import pdf 10 | 11 | 12 | class Signer: 13 | def __init__(self, cert, sig, tosign): 14 | self.cert = cert 15 | self.sig = sig 16 | self.tosign = tosign 17 | self.mech = None 18 | 19 | def certificate(self): 20 | return 1, self.cert 21 | 22 | def sign(self, keyid, data, mech): 23 | if self.tosign: 24 | assert self.tosign == data 25 | self.tosign = data 26 | self.mech = mech 27 | if self.sig is None: 28 | sig = None 29 | if mech == "sha256": 30 | sig = b"\0" * 256 31 | return sig 32 | return self.sig 33 | 34 | 35 | def main(): 36 | def attrs(signed_value): 37 | result = [ 38 | cms.CMSAttribute( 39 | {"type": cms.CMSAttributeType("content_type"), "values": ("data",)} 40 | ), 41 | cms.CMSAttribute( 42 | { 43 | "type": cms.CMSAttributeType("message_digest"), 44 | "values": (signed_value,), 45 | } 46 | ), 47 | cms.CMSAttribute( 48 | { 49 | "type": cms.CMSAttributeType("signing_time"), 50 | "values": (cms.Time({"utc_time": core.UTCTime(signed_time)}),), 51 | } 52 | ), 53 | ] 54 | return result 55 | 56 | dct = { 57 | "sigflags": 3, 58 | "sigpage": 0, 59 | "sigbutton": True, 60 | "contact": "mak@trisoft.com.pl", 61 | "location": "Szczecin", 62 | "reason": "Dokument podpisany cyfrowo", 63 | "signature": "Dokument podpisany cyfrowo", 64 | "signaturebox": (0, 0, 100, 100), 65 | "aligned": 16384, 66 | "attrs": attrs, 67 | "newid": "1", 68 | } 69 | 70 | pdfname = 'pdf.pdf' 71 | if len (sys.argv) > 1: 72 | pdfname = sys.argv[1] 73 | try: 74 | config = open(pdfname + ".json", "rt").read() 75 | config = json.loads(config) 76 | except FileNotFoundError: 77 | when = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") 78 | config = { 79 | 'when': when, 80 | 'certificate': open("cert-hsm-user1.pem", "rt").read(), 81 | 'signed_bytes': None, 82 | 'tosign': None, 83 | 'id': hashlib.md5(when.encode()).hexdigest() 84 | } 85 | dct['id'] = config['id'].encode() 86 | when = datetime.datetime.strptime(config['when'], "%Y-%m-%d %H:%M:%S") 87 | dct["signingdate"] = when.strftime("%Y%m%d%H%M%S+00'00'").encode() 88 | signed_time = datetime.datetime( 89 | when.year, when.month, when.day, when.hour, when.minute, when.second, 0, util.timezone.utc 90 | ) 91 | cert = config['certificate'].encode('ascii') 92 | signed_bytes = config['signed_bytes'] 93 | if signed_bytes is not None: 94 | signed_bytes = base64.decodebytes(signed_bytes.encode('ascii')) 95 | tosign = config['tosign'] 96 | if tosign is not None: 97 | tosign = base64.decodebytes(tosign.encode('ascii')) 98 | 99 | clshsm = Signer(cert, signed_bytes, tosign) 100 | 101 | datau = open(pdfname, "rb").read() 102 | cls = pdf.cms.SignedData() 103 | datas = cls.sign(datau, dct, None, None, [], "sha256", clshsm, mode="sign") 104 | 105 | if signed_bytes is None: 106 | config['tosign'] = b"".join(base64.encodebytes(clshsm.tosign).split()).decode('ascii') 107 | json.dump(config, open(pdfname + ".json", "wt"), indent=4) 108 | else: 109 | fname = pdfname.replace(".pdf", "-signed-cms-hash.pdf") 110 | with open(fname, "wb") as fp: 111 | fp.write(datau) 112 | fp.write(datas) 113 | 114 | 115 | main() 116 | -------------------------------------------------------------------------------- /examples/xml-hsm-certum-enveloping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | from certum import dllpath 4 | from lxml import etree 5 | import PyKCS11 as PK11 6 | from cryptography import x509 7 | from cryptography.hazmat.backends import default_backend 8 | from cryptography.hazmat.primitives import serialization 9 | 10 | from endesive import xades, signer, hsm 11 | 12 | 13 | 14 | class Signer(hsm.HSM): 15 | def certificate(self): 16 | self.login("profil bezpieczny", "9593") 17 | keyid = [ 18 | 0x5E, 19 | 0x9A, 20 | 0x33, 21 | 0x44, 22 | 0x8B, 23 | 0xC3, 24 | 0xA1, 25 | 0x35, 26 | 0x33, 27 | 0xC7, 28 | 0xC2, 29 | 0x02, 30 | 0xF6, 31 | 0x9B, 32 | 0xDE, 33 | 0x55, 34 | 0xFE, 35 | 0x83, 36 | 0x7B, 37 | 0xDE, 38 | ] 39 | # keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] 40 | keyid = bytes(keyid) 41 | try: 42 | pk11objects = self.session.findObjects( 43 | [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] 44 | ) 45 | all_attributes = [ 46 | # PK11.CKA_SUBJECT, 47 | PK11.CKA_VALUE, 48 | # PK11.CKA_ISSUER, 49 | # PK11.CKA_CERTIFICATE_CATEGORY, 50 | # PK11.CKA_END_DATE, 51 | PK11.CKA_ID, 52 | ] 53 | 54 | for pk11object in pk11objects: 55 | try: 56 | attributes = self.session.getAttributeValue( 57 | pk11object, all_attributes 58 | ) 59 | except PK11.PyKCS11Error as e: 60 | continue 61 | 62 | attrDict = dict(list(zip(all_attributes, attributes))) 63 | cert = bytes(attrDict[PK11.CKA_VALUE]) 64 | if keyid == bytes(attrDict[PK11.CKA_ID]): 65 | return keyid, cert 66 | finally: 67 | self.logout() 68 | return None, None 69 | 70 | def sign(self, keyid, data, mech): 71 | self.login("profil bezpieczny", "9593") 72 | try: 73 | privKey = self.session.findObjects( 74 | [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] 75 | )[0] 76 | mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) 77 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 78 | return bytes(sig) 79 | finally: 80 | self.logout() 81 | 82 | 83 | def main(): 84 | clshsm = Signer(dllpath) 85 | keyid, cert = clshsm.certificate() 86 | 87 | def signproc(tosign, algosig): 88 | return clshsm.sign(keyid, tosign, algosig) 89 | 90 | data = open("xml.xml", "rb").read() 91 | cert = x509.load_der_x509_certificate(cert, backend=default_backend()) 92 | certcontent = cert.public_bytes(serialization.Encoding.DER) 93 | 94 | for tspurl, tspcred in ( 95 | (None, None), 96 | ("http://public-qlts.certum.pl/qts-17", None) 97 | ): 98 | cls = xades.BES() 99 | doc = cls.enveloping( 100 | "dokument.xml", 101 | data, 102 | "application/xml", 103 | cert, 104 | certcontent, 105 | signproc, 106 | False, 107 | False, 108 | False, 109 | tspurl, 110 | tspcred, 111 | ) 112 | data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) 113 | if tspurl is None: 114 | open("xml-hsm-certum-enveloping.xml", "wb").write(data) 115 | else: 116 | open("xml-hsm-certum-enveloping-t.xml", "wb").write(data) 117 | 118 | 119 | if __name__ == "__main__": 120 | main() 121 | -------------------------------------------------------------------------------- /examples/pdf-sign-cms-hsm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # *-* coding: utf-8 *-* 3 | import sys 4 | from endesive import pdf, hsm 5 | 6 | import os 7 | import sys 8 | import sysconfig 9 | import datetime 10 | from cryptography import x509 11 | from cryptography.hazmat import backends 12 | 13 | os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' 14 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): 15 | open('softhsm2.conf', 'wt').write('''\ 16 | log.level = DEBUG 17 | directories.tokendir = %s/softhsm2/ 18 | objectstore.backend = file 19 | slots.removable = false 20 | ''' % os.getcwd()) 21 | if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): 22 | os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) 23 | 24 | # 25 | #!/bin/bash 26 | #SOFTHSM2_CONF=softhsm2.conf 27 | #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 28 | #softhsm2-util --show-slots 29 | # 30 | 31 | if sys.platform == 'win32': 32 | dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' 33 | else: 34 | dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") 35 | 36 | import PyKCS11 as PK11 37 | 38 | class Signer(hsm.HSM): 39 | def certificate(self): 40 | self.login("endesieve", "secret1") 41 | keyid = bytes((0x66,0x66,0x90)) 42 | try: 43 | pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) 44 | all_attributes = [ 45 | #PK11.CKA_SUBJECT, 46 | PK11.CKA_VALUE, 47 | #PK11.CKA_ISSUER, 48 | #PK11.CKA_CERTIFICATE_CATEGORY, 49 | #PK11.CKA_END_DATE, 50 | PK11.CKA_ID, 51 | ] 52 | 53 | for pk11object in pk11objects: 54 | try: 55 | attributes = self.session.getAttributeValue(pk11object, all_attributes) 56 | except PK11.PyKCS11Error as e: 57 | continue 58 | 59 | attrDict = dict(list(zip(all_attributes, attributes))) 60 | cert = bytes(attrDict[PK11.CKA_VALUE]) 61 | if keyid == bytes(attrDict[PK11.CKA_ID]): 62 | return keyid, cert 63 | finally: 64 | self.logout() 65 | return None, None 66 | 67 | def sign(self, keyid, data, mech): 68 | self.login("endesieve", "secret1") 69 | try: 70 | privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] 71 | mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) 72 | sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) 73 | return bytes(sig) 74 | finally: 75 | self.logout() 76 | 77 | def main(): 78 | tspurl = "http://time.certum.pl" 79 | tspurl = "http://public-qlts.certum.pl/qts-17" 80 | 81 | ocspurl = 'https://ocsp.certum.pl/' 82 | ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() 83 | ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) 84 | 85 | date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) 86 | date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') 87 | dct = { 88 | 'sigflags': 3, 89 | 'contact': 'mak@trisoft.com.pl', 90 | 'location': 'Szczecin', 91 | 'signingdate': date.encode(), 92 | 'reason': 'Dokument podpisany cyfrowo', 93 | 'application': 'app:xyz', 94 | } 95 | 96 | clshsm = Signer(dllpath) 97 | 98 | fname = 'pdf.pdf' 99 | if len (sys.argv) > 1: 100 | fname = sys.argv[1] 101 | 102 | datau = open(fname, 'rb').read() 103 | datas = pdf.cms.sign(datau, dct, 104 | None, None, 105 | [], 106 | 'sha256', 107 | clshsm, 108 | tspurl, 109 | ocspurl=ocspurl, 110 | ocspissuer=ocspissuer 111 | ) 112 | fname = fname.replace('.pdf', '-signed-cms-hsm.pdf') 113 | with open(fname, 'wb') as fp: 114 | fp.write(datau) 115 | fp.write(datas) 116 | 117 | 118 | main() 119 | -------------------------------------------------------------------------------- /endesive/email/decrypt.py: -------------------------------------------------------------------------------- 1 | # *-* coding: utf-8 *-* 2 | import sys 3 | from email import message_from_string 4 | 5 | from asn1crypto import cms 6 | from cryptography.hazmat.backends import default_backend 7 | from cryptography.hazmat.primitives import hashes 8 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 9 | from cryptography.hazmat.primitives.asymmetric import padding 10 | from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes 11 | 12 | 13 | class DecryptedData(object): 14 | 15 | def decrypt(self, data: str, key: PrivateKeyTypes) -> bytes: 16 | msg = message_from_string(data) 17 | data = None 18 | for part in msg.walk(): 19 | # multipart/* are just containers 20 | if part.get_content_maintype() == 'multipart': 21 | continue 22 | if part.get_content_type() not in ( 23 | 'application/x-pkcs7-mime', 24 | 'application/pkcs7-mime', 25 | ): 26 | continue 27 | data = part.get_payload(decode=True) 28 | break 29 | if data is None: 30 | raise ValueError('No encrypted part found in the message') 31 | 32 | signed_data = cms.ContentInfo.load(data)['content'] 33 | # signed_data.debug() 34 | 35 | algo = signed_data['encrypted_content_info']['content_encryption_algorithm']['algorithm'].native 36 | param = signed_data['encrypted_content_info']['content_encryption_algorithm']['parameters'].native 37 | edata = signed_data['encrypted_content_info']['encrypted_content'].native 38 | pkey = signed_data['recipient_infos'].native[0]['encrypted_key'] 39 | 40 | keyalgo = signed_data['recipient_infos'].native[0]['key_encryption_algorithm'] 41 | if keyalgo['algorithm'] == 'rsaes_oaep': 42 | keyparam = keyalgo['parameters'] 43 | mga = keyparam['mask_gen_algorithm'] 44 | mgh = getattr(hashes, mga['parameters']['algorithm'].upper())() 45 | pad = padding.OAEP( 46 | mgf=getattr(padding, mga['algorithm'].upper())(algorithm=mgh), 47 | algorithm=getattr(hashes, keyparam['hash_algorithm']['algorithm'].upper())(), 48 | label=keyparam['p_source_algorithm']['parameters'] 49 | ) 50 | udata = key.decrypt(pkey, pad) 51 | elif keyalgo['algorithm'] == 'rsaes_pkcs1v15': 52 | udata = key.decrypt(pkey, padding.PKCS1v15()) 53 | else: 54 | raise ValueError('Unknown key algorithm', keyalgo['algorithm']) 55 | 56 | algorithm, mode = algo.split('_', 1) 57 | algorithm = algorithm.upper() 58 | if algorithm in ( 59 | 'AES128', 60 | 'AES192', 61 | 'AES256', 62 | ): 63 | cipher = Cipher( 64 | algorithms.AES(udata), 65 | getattr(modes, mode.upper())(param), 66 | default_backend() 67 | ) 68 | elif algorithm == 'TRIPLEDES': 69 | # XXX will be removed in version 48.0.0 70 | from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES 71 | # XXX howto decode parameters to CBC mode ? 72 | mode = 'cbc' 73 | cipher = Cipher( 74 | TripleDES(udata), 75 | getattr(modes, mode.upper())(param), 76 | default_backend() 77 | ) 78 | else: 79 | raise ValueError('Unknown algorithm', algo) 80 | 81 | decryptor = cipher.decryptor() 82 | udata = decryptor.update(edata) + decryptor.finalize() 83 | #if keyalgo['algorithm'] != 'rsaes_oaep': 84 | nb = ord(udata[-1]) if sys.version[0] < '3' else udata[-1] 85 | udata = udata[:-nb] 86 | return udata 87 | 88 | 89 | def decrypt(data: str, key: PrivateKeyTypes) -> bytes: 90 | """ 91 | Decrypt the given data string using the provided private key. 92 | 93 | :param data: The encrypted data as a string. 94 | :param key: The private key used for decryption. 95 | :return: The decrypted data as bytes. 96 | """ 97 | cls = DecryptedData() 98 | return cls.decrypt(data, key) 99 | -------------------------------------------------------------------------------- /endesive/pdf/PyPDF2_annotate/util/text.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Text Utils 4 | ~~~~~~~~~~ 5 | 6 | :copyright: Copyright 2019 Autodesk, Inc. 7 | :license: MIT, see LICENSE for details. 8 | """ 9 | 10 | 11 | def unshift_token(text): 12 | """Remove a token from the front of a string. 13 | 14 | :param str text: 15 | :returns: {'text': str, 'separator': str, 'remainder': str} 16 | """ 17 | if len(text) == 0: 18 | return {'text': text, 'separator': '', 'remainder': ''} 19 | 20 | token = '' 21 | for i in range(0, len(text)): 22 | char = text[i] 23 | if (char == ' ' and (len(token) >= 1 and token[i - 1] == ' ')): 24 | token += char 25 | elif (char == ' ' and len(token) == 0): 26 | token += char 27 | elif char == ' ': 28 | return {'text': token, 'separator': ' ', 'remainder': text[i + 1:]} 29 | elif char == '\n': 30 | return { 31 | 'text': token, 32 | 'separator': '\n', 33 | 'remainder': text[i + 1:], 34 | } 35 | elif (len(token) >= 1 and token[i - 1] == ' '): 36 | return { 37 | 'text': token, 38 | 'separator': '', 39 | 'remainder': text[len(token):], 40 | } 41 | else: 42 | token += char 43 | 44 | return {'text': token, 'separator': '', 'remainder': ''} 45 | 46 | 47 | def unshift_line(text, measure, max_length): 48 | """Remove a line of text from a string. 49 | 50 | :param str text: text to be broken 51 | :param func measure: function that takes a string and returns its width 52 | :param int max_length: max width of each line 53 | :returns: {'text': str, 'remainder': str} 54 | """ 55 | line = '' 56 | token = {'text': '', 'separator': '', 'remainder': text} 57 | while True: 58 | token = unshift_token(token['remainder']) 59 | token_text = token['text'] 60 | remainder = token['remainder'] 61 | separator = token['separator'] 62 | if len(line) == 0: 63 | if len(token_text) > 0: 64 | # This allows us to add partial tokens for the first token 65 | for char in token_text: 66 | if measure(line + char) > max_length: 67 | line = char if len(line) == 0 else line 68 | return { 69 | 'text': line, 70 | 'remainder': text[len(line):], 71 | } 72 | else: 73 | line += char 74 | if separator == '\n': 75 | return {'text': line, 'remainder': remainder} 76 | 77 | line += separator 78 | else: 79 | return { 80 | 'text': line, 81 | 'remainder': text[len(line) + len(separator):], 82 | } 83 | else: 84 | if measure(line + token_text) <= max_length: 85 | line += token_text 86 | if separator == '\n' or remainder == '': 87 | return {'text': line, 'remainder': remainder} 88 | else: 89 | line += separator 90 | else: 91 | return {'text': line, 'remainder': text[len(line):]} 92 | 93 | 94 | def get_wrapped_lines(text, measure, max_length): 95 | """Break a string of text into lines wrapped to max_length. 96 | 97 | The algorithm is the same one used in the PGBS TextElement in web-viewer, 98 | to maintain consistency in line breaks. 99 | 100 | :param str text: text to be broken 101 | :param func measure: function that takes a string and returns its width 102 | :param int max_length: max width of each line 103 | :returns: list of strings 104 | """ 105 | line = unshift_line(text, measure, max_length) 106 | lines = [line['text']] 107 | while (len(line['remainder']) > 0): 108 | line = unshift_line(line['remainder'], measure, max_length) 109 | lines.append(line['text']) 110 | return lines 111 | --------------------------------------------------------------------------------