Skip to main content

dhcrypt

OpenSSL-interoperable Finite-Field Diffie-Hellman (FFDH) key exchange and AES-256-GCM authenticated encryption in Python.

PyPI version Python Versions Tests Coverage Code Style: Black Type Checking: Pyright OpenSSL Compatible License: MIT


Features

  • OpenSSL Interoperability: Seamlessly exchanges keys with openssl genpkey -paramfile, openssl pkeyutl -derive, and standard OpenSSL 3.x / legacy 1.x workflows.
  • PKCS#3 ASN.1 Engine: Built-in parser that correctly handles optional privateValueLength fields from openssl genpkey -genparam.
  • Authenticated Encryption: AES-256-GCM authenticated cipher preventing unauthorized tampering and ciphertext manipulation.
  • Robust Key Derivation: HKDF-SHA256 context-bound symmetric key derivation.
  • Active Subgroup Protection: Miller-Rabin safe-prime subgroup checks ($y^q \equiv 1 \pmod p$) guarding against small-subgroup confinement attacks.
  • Secure File Permissions: Enforces restrictive 0600 POSIX file permissions for private keys by default.
  • Zero-Dependency CLI & Library: Run directly as a CLI tool or import into any Python project.

Installation

Using pip

pip install dhcrypt

Using Poetry

poetry add dhcrypt

Quick Start (CLI)

Perform a complete Diffie-Hellman key exchange and encrypted communication in five commands:

# 1. Generate DH group parameters
dhcrypt genparams --bits 2048 -o dhp.pem

# 2. Alice and Bob generate keypairs
dhcrypt keygen -p dhp.pem --priv alice.key --pub alice.pub
dhcrypt keygen -p dhp.pem --priv bob.key --pub bob.pub

# 3. Derive shared secret (or encrypt directly using peer keys)
dhcrypt derive --priv alice.key --peer bob.pub --fingerprint -o secret.bin

# 4. Encrypt message
dhcrypt encrypt -k secret.bin -p message.txt -o message.enc

# 5. Decrypt message
dhcrypt decrypt -k secret.bin -p message.enc -o recovered.txt

Command-Line Interface Reference

usage: dhcrypt [-h] {genparams,keygen,derive,encrypt,decrypt} ...

genparams

Generate safe-prime Diffie-Hellman parameters serialized in PKCS#3 PEM format.

dhcrypt genparams [--bits BITS] [-o OUT]
  • --bits: Bit length of the prime modulus (default: 2048).
  • -o, --out: Output path (- for stdout, default: -).

keygen

Generate a private key (PKCS#8 format, mode 0600) and public key (SPKI format) from group parameters.

dhcrypt keygen -p PARAMS --priv PRIV --pub PUB [--private-length BITS] [--force]
  • -p, --params: Path to DH parameters PEM (or any DH key PEM carrying parameters).
  • --priv: Output path for the private key (mode 0600).
  • --pub: Output path for the public key.
  • --private-length: Exponent bit length (e.g., 256 for short exponent generation).
  • --force: Overwrite existing private key file if present.

derive

Derive the raw shared secret between our private key and a peer's public key.

dhcrypt derive --priv PRIV --peer PEER [-o OUT] [--hex] [--fingerprint] [--strip-zeros]
  • --priv: Path to our private key PEM.
  • --peer: Path to peer's public key PEM.
  • -o, --out: Output path (- for stdout).
  • --hex: Encode secret as hexadecimal text.
  • --fingerprint: Output SHA-256 fingerprint of the shared secret to stderr.
  • --strip-zeros: Strip leading zero bytes (reproduces legacy OpenSSL 1.x / DH_compute_key behavior).

encrypt

Encrypt a payload using AES-256-GCM.

# Using derived secret file:
dhcrypt encrypt -k SECRET -p PAYLOAD [-o OUT]

# Or deriving directly from keys:
dhcrypt encrypt --priv PRIV --peer PEER -p PAYLOAD [-o OUT]
  • -k, --pem: Path to file containing the shared secret (raw bytes or hex).
  • --priv and --peer: Derive secret directly using our private key and peer's public key.
  • -p, --payload: Path to input plaintext (- for stdin).
  • -o, --out: Path to output ciphertext (- for stdout).

decrypt

Verify authentication tag and decrypt an AES-256-GCM ciphertext payload.

# Using derived secret file:
dhcrypt decrypt -k SECRET -p PAYLOAD [-o OUT]

# Or deriving directly from keys:
dhcrypt decrypt --priv PRIV --peer PEER -p PAYLOAD [-o OUT]

Python API Usage

dhcrypt can be imported and integrated directly into Python applications:

from dhcrypt import (
    generate_parameters_pem,
    generate_keypair_pem,
    derive_shared_secret,
    encrypt_message,
    decrypt_message,
)

# 1. Generate DH group parameters
params_pem = generate_parameters_pem(key_size=2048)

# 2. Parties generate keypairs
alice_priv, alice_pub, alice_bits = generate_keypair_pem(params_pem)
bob_priv, bob_pub, bob_bits = generate_keypair_pem(params_pem)

# 3. Derive identical shared secrets
secret_alice = derive_shared_secret(alice_priv, bob_pub)
secret_bob = derive_shared_secret(bob_priv, alice_pub)
assert secret_alice == secret_bob

# 4. Encrypt and decrypt payloads
plaintext = b"Encrypted transmission over secure channel."
ciphertext = encrypt_message(secret_alice, plaintext)

decrypted = decrypt_message(secret_bob, ciphertext)
assert decrypted == plaintext

Low-Level Primitives

from dhcrypt import (
    DHParams,
    compute_shared_secret,
    derive_symmetric_key,
    encrypt_payload,
    decrypt_payload,
    validate_peer_public,
)

params = DHParams(p=0xFFFFFFFFFFFFFFFF, g=2)
validate_peer_public(peer_public_int, params)
raw_secret = compute_shared_secret(private_int, peer_public_int, params)

# HKDF key derivation & AES-GCM
key = derive_symmetric_key(raw_secret, salt=b"custom-salt", info=b"app-context")
encrypted = encrypt_payload(key, b"Sensitive data")
decrypted = decrypt_payload(key, encrypted)

Security & Wire Format Specifications

  • Wire Format: Ciphertext payloads output by encrypt use the format: $$\text{Payload} = \text{Nonce}{12\text{ bytes}} \parallel \text{Ciphertext} \parallel \text{Tag}{16\text{ bytes}}$$
  • Key Derivation: Shared secrets derived from Diffie-Hellman exchange are passed through HKDF-SHA256 (info=b"stompzone-dh-kex-context") to derive a 256-bit symmetric encryption key.
  • Subgroup Validation: Peer public values are strictly validated against $[2, p - 2]$. For safe-prime groups where generator $g$ generates an order-$q$ subgroup, $y^q \equiv 1 \pmod p$ is enforced to prevent small-subgroup confinement attacks.
  • OpenSSL Interoperability: Handles PKCS#3 ASN.1 structures with optional privateValueLength parameter attributes that cause errors in naive OpenSSL/cryptography integrations.

Test Suite & Quality Assurance

Run the test suite with coverage reporting:

poetry run pytest

Test Coverage Summary

Name                       Stmts   Miss  Cover
----------------------------------------------
dhcrypt\__init__.py           14      0   100%
dhcrypt\__main__.py            2      0   100%
dhcrypt\cli.py                89      0   100%
dhcrypt\constants.py           6      0   100%
dhcrypt\dh.py                 33      0   100%
dhcrypt\exceptions.py          6      0   100%
dhcrypt\io.py                 45      0   100%
dhcrypt\math.py               52      0   100%
dhcrypt\models.py             18      0   100%
dhcrypt\serialization.py      97      0   100%
dhcrypt\service.py            27      0   100%
dhcrypt\symmetric.py          44      0   100%
----------------------------------------------
TOTAL                        433      0   100%

License

MIT License. Copyright (c) 2026 DJ Stomp.

Metadata

Release files for dhcrypt 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dhcrypt 1.0.0
File Size Uploaded
dhcrypt-1.0.0.tar.gz 13.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dhcrypt 1.0.0
File Interpreter ABI Platform
dhcrypt-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.9 kB

Release files / dhcrypt-1.0.0.tar.gz

Download URL dhcrypt-1.0.0.tar.gz
Size 13.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ec95e1e277011be0e567b9ba435053871bc089d9b6dc5d97376c59aca1481088
BLAKE2b-256 checksum
How to use checksums
0907bda903c2f989b5c95a9614c69a655df069e61fc6f2bdd4792626d4c80e50
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.4 CPython/3.13.0 Windows/11

Release files / dhcrypt-1.0.0-py3-none-any.whl

Download URL dhcrypt-1.0.0-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
833af9403e64926554ac4d726f60f2ae53661363a45f9a4987206ddc5868baeb
BLAKE2b-256 checksum
How to use checksums
b7cd0dd4dfabe45a9b9f94fb585147b8f8ecf78ca2d263505c9002e437901586
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.1.4 CPython/3.13.0 Windows/11

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page