PGPy

repository·master·Indexed 43 days ago

https://github.com/securityinnovation/pgpy

A Python library for implementing Pretty Good Privacy (PGP) conforming to the OpenPGP specification per RFC 4880. It provides tools for managing PGPKey, PGPMessage, and PGPSignature objects, supporting asymmetric encryption (RSA, ECDH), symmetric encryption with passphrases, digital signatures, and ASCII-armored export.

Tokens
8.7K
Snippets
35
Records
43
Agent score
53%

What's inside PGPy

  1. Platform-specific notes for Windows and macOS

    master

    Windows

    PGPy has not been formally tested on Windows. While it is expected to work, users should report any issues via the GitHub issue tracker.

    macOS

    Users may experience limited functionality if a more capable version of OpenSSL is not installed. For guidance on setting up OpenSSL, refer to the cryptography library's documentation on building for macOS.

  2. OpenPGP RFC compliance and implementation progress

    master

    PGPy is working towards full compliance with OpenPGP standards. The current implementation focus is on RFC 4880 (the latest complete OpenPGP Message Format specification), which supersedes RFC 1991 and RFC 2440.

    Key areas of compliance include:

    • Packet Support: Various versioned (v1, v3, v4) and unversioned packets (Compressed Data, Literal Data, etc.).
    • Key Types: Support for RSA, DSA, and ElGamal.
    • Storage Formats: Support for ASCII armored blocks, binary packets, and GPG (<= 2.0.x) keyrings.
    • Cryptographic Actions: Encryption, decryption, key generation, signing, and verification for supported key types.
    • Signature Subpackets: Extensive support for subpackets like Signature Creation Time, Expiration, and Revocation keys.

    Note that some features, such as KBX storage, HKP key server interaction, and certain ElGamal/Twofish operations, may not yet be implemented.

  3. Supported Elliptic Curve Cryptography (RFC 6637)

    master

    PGPy implements extensions for Elliptic Curve Cryptography as defined in RFC 6637. This includes support for:

    Supported Key Types

    • ECDH: Elliptic Curve Diffie-Hellman
    • ECDSA: Elliptic Curve Digital Signature Algorithm

    Supported Curves

    • NIST P-256
    • NIST P-386
    • NIST P-521

    Supported Actions

    • ECDH: Loading keys, generating keys/subkeys, and KDF (Key Derivation Function) encoding/decoding for encryption/decryption.
    • ECDSA: Comprehensive support for loading, generating, signing (detached, inline, one-pass, messages, keys, etc.), verifying, and revocation actions.
  4. Load PGP keys individually or from a keyring

    master

    Loading Individually

    • From a blob: Use pgpy.PGPKey.from_blob(keyblob) to parse ASCII or binary data.
    • From a file: Use pgpy.PGPKey.from_file('path/to/key.asc').
    • Parsing into existing object: Use empty_key.parse(keyblob) on an instantiated PGPKey object.

    Loading into a Keyring

    If managing multiple keys, use pgpy.PGPKeyring. You can initialize it with a list of file paths or use the .load() method to load keys from a list of files. The .load() method returns a set of fingerprints for all keys and subkeys loaded during that operation.

    import pgpy
    import glob
    import os
    
    # Load from files into a keyring
    kr = pgpy.PGPKeyring()
    loaded_fingerprints = kr.load(glob.glob(os.path.expanduser('~/.gnupg/*ring.gpg')))
    
    # Load a single key from a file
    key, _ = pgpy.PGPKey.from_file('path/to/key.asc')
    
    # Load a single key from a blob
    key, _ = pgpy.PGPKey.from_blob(keyblob)
  5. Install build dependencies for PGPy on Linux

    master

    Building PGPy on Linux requires a C compiler, Python headers, OpenSSL headers, and libffi to support the underlying cryptography library. Depending on your distribution, install the following:

    Debian/Ubuntu

    $ sudo apt install build-essential libssl-dev libffi-dev python-dev

    Note: You may need python3-dev if using Python 3.

    Alpine Linux

    $ apk add build-base libressl-dev libffi-dev python-dev

    Fedora/RHEL derivatives

    $ sudo yum install gcc libffi-devel python-devel openssl-devel
  6. Protect and unlock secret keys

    master

    Passphrase Protection

    To protect a private key with a passphrase, use key.protect(passphrase, symmetric_algorithm, hash_algorithm). After this, key.is_protected will be True.

    Unlocking Keys

    To use a protected key, use the key.unlock(passphrase) context manager. This is the recommended way to handle secret material as it automatically removes the unprotected key material from the object once the block is exited. If the passphrase is incorrect, it raises a PGPDecryptionError.

    import pgpy
    from pgpy.constants import SymmetricKeyAlgorithm, HashAlgorithm
    
    # Protecting a key
    key.protect("C0rrectPassphr@se", SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256)
    
    # Unlocking a key using a context manager
    with key.unlock("C0rrectPassphr@se"):
        # key.is_unlocked is True inside this block
        # Perform cryptographic operations here
        pass
    # key.is_unlocked is False once the block exits
  7. Disable usage flag checks on a PGPKey

    master

    If a key was created without the correct usage flags (e.g., EncryptStorage, EncryptCommunications), PGPy will raise a PGPError when attempting to use it for encryption.

    If you are certain you need to bypass this check, set the private attribute _require_usage_flags to False on the PGPKey instance before performing the operation.

    from pgpy import PGPKey, PGPMessage
    
    key, _ = PGPKey.from_file('path/to/key_without_usage_flags.asc')
    # Disable the check
    key._require_usage_flags = False
    
    message = PGPMessage.new('secret message')
    encrypted_phrase = key.encrypt(message)
  8. Export PGP messages to binary or ASCII-armored formats

    master

    Messages can be exported in OpenPGP compliant formats.

    In Python 3, use bytes() for binary output and str() for ASCII-armored output. If the message is a cleartext message, the ASCII-armored output will properly canonicalize and dash-escape the message text.

    # Python 3 usage
    
    # Export to binary format
    msgbytes = bytes(message)
    
    # Export to ASCII-armored format
    msgstr = str(message)