PyHanko

0.34.1 · active · verified Thu Apr 09

PyHanko is a Python library designed for stamping and digitally signing PDF files, offering extensive functionality for handling digital signatures, including support for various PAdES profiles and cryptographic operations. It is actively maintained with frequent minor releases, currently at version 0.34.1, and aims to cover the digital signing features of the PDF standard comprehensively.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to digitally sign a PDF document using `pyhanko` with a simple signer. It covers loading the signing key and certificate, applying a signature to a PDF, and saving the output. For a real application, you would replace the dummy key/cert paths with your actual cryptographic materials.

import io
import os

from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
from pyhanko.sign import signers

def sign_document_example(input_path, output_path, key_path, cert_path, ca_chain_path=None, key_passphrase=None):
    # Create dummy key and cert files for runnable example
    with open('dummy_key.pem', 'w') as f: f.write('-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----') # Placeholder
    with open('dummy_cert.pem', 'w') as f: f.write('-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----') # Placeholder
    if ca_chain_path: # Create dummy CA chain if path provided
        with open('dummy_ca_chain.pem', 'w') as f: f.write('-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----') # Placeholder

    # In a real scenario, replace 'dummy_key.pem' and 'dummy_cert.pem'
    # with paths to your actual signer key and certificate.
    # key_passphrase should be bytes, e.g., b'your_password'

    # Load the signer key and certificate
    cms_signer = signers.SimpleSigner.load(
        key_path or 'dummy_key.pem',
        cert_path or 'dummy_cert.pem',
        ca_chain_files=(ca_chain_path or 'dummy_ca_chain.pem',) if ca_chain_path else None,
        key_passphrase=key_passphrase
    )

    with open(input_path, 'rb') as doc_input:
        w = IncrementalPdfFileWriter(doc_input)
        out = signers.sign_pdf(
            w,
            signers.PdfSignatureMetadata(field_name='Signature1'), # Use an existing field or 'Signature1' will be created
            signer=cms_signer,
        )

        with open(output_path, 'wb') as doc_output:
            doc_output.write(out.read())

    print(f"Document signed: {output_path}")

# Example usage (requires a dummy PDF and actual key/cert files in a real scenario)
# You can create a dummy PDF file like 'input.pdf' for testing.
# Replace 'your_key.pem', 'your_cert.pem', 'your_ca_chain.pem' with actual paths.
# To run this example, ensure you have a 'input.pdf' file.
# And replace the '...'(s) with actual PEM contents from your test certificates if you want to run it end to end.
# try:
#     # Create a minimal dummy PDF for testing if it doesn't exist
#     if not os.path.exists('input.pdf'):
#         from PyPDF2 import PdfWriter
#         writer = PdfWriter()
#         writer.add_blank_page(width=72, height=72)
#         with open('input.pdf', 'wb') as f: writer.write(f)
#
#     sign_document_example(
#         input_path='input.pdf',
#         output_path='signed_output.pdf',
#         key_path=os.environ.get('PYHANKO_SIGNER_KEY_PATH', 'dummy_key.pem'),
#         cert_path=os.environ.get('PYHANKO_SIGNER_CERT_PATH', 'dummy_cert.pem'),
#         ca_chain_path=os.environ.get('PYHANKO_CA_CHAIN_PATH', 'dummy_ca_chain.pem'),
#         key_passphrase=os.environ.get('PYHANKO_KEY_PASSPHRASE', '').encode('utf-8')
#     )
# finally:
#     # Clean up dummy files
#     for f in ['dummy_key.pem', 'dummy_cert.pem', 'dummy_ca_chain.pem']:
#         if os.path.exists(f): os.remove(f)

view raw JSON →