Protocols (quantum_safe.protocols)¶
Higher-level protocol helpers built on top of the KEM and signature primitives.
Envelope¶
- class quantum_safe.protocols.envelope.Envelope[source]¶
Bases:
objectAuthenticated encryption using hybrid KEM + AES-256-GCM.
This is a class with only class methods — you don’t instantiate it. Think of it as a namespace for seal() and open().
Example:
# Sender: sealed = Envelope.seal(b"top secret", recipient_public_key) wire = sealed.to_bytes() # send this over the network # Recipient: msg = sealed.from_bytes(wire) plain = Envelope.open(msg, recipient_secret_key)
- classmethod seal(plaintext, recipient_public_key, aad=b'', kem=None)[source]¶
Encrypt plaintext to the recipient’s public key.
- Parameters:
plaintext (
bytes) – The data to encrypt. No size limit.recipient_public_key (
PublicKey) – Recipient’s HybridKEM public key.aad (
bytes) – Additional authenticated data. Included unencrypted in the envelope but authenticated by GCM — any modification fails decryption. Use for metadata you want visible but protected (e.g. recipient ID, timestamp, content type).kem (
HybridKEM|None) – HybridKEM instance to use. If None, creates a default HybridKEM() matching the key’s algorithm.
- Return type:
- Returns:
SealedMessage that can be decrypted with Envelope.open().
- Raises:
UnsupportedAlgorithm – if the key’s algorithm isn’t a known hybrid KEM combination.
- classmethod open(sealed, recipient_secret_key, kem=None)[source]¶
Decrypt a SealedMessage.
- Parameters:
sealed (
SealedMessage) – SealedMessage from Envelope.seal() or deserialized from the wire.recipient_secret_key (
SecretKey) – The recipient’s HybridKEM secret key.kem (
HybridKEM|None) – HybridKEM instance. If None, auto-created from the envelope’s algorithm field.
- Return type:
- Returns:
Original plaintext bytes.
- Raises:
DecapsulationError – if KEM decapsulation fails.
cryptography.exceptions.InvalidTag – if the ciphertext is tampered or the wrong key is used (GCM authentication failure). We let this propagate from cryptography directly — don’t catch it.
- class quantum_safe.protocols.envelope.SealedMessage(version, algorithm, kem_ct, nonce, ciphertext, aad=b'')[source]¶
Bases:
objectA ciphertext envelope produced by Envelope.seal().
All fields are needed to decrypt. The aad field is authenticated but not encrypted — it’s safe to inspect without the decryption key.
- version¶
Envelope format version.
- algorithm¶
KEM algorithm used (e.g. “X25519+ML-KEM-768”).
- kem_ct¶
KEM ciphertext bytes (HybridCipherText wire format).
- nonce¶
12-byte AES-GCM nonce. Never reused.
- ciphertext¶
AES-256-GCM encrypted payload including 16-byte tag.
- aad¶
Additional authenticated data. Visible but authenticated.
- Parameters:
- classmethod from_bytes(data)[source]¶
Deserialize from bytes produced by to_bytes().
- Parameters:
data (
bytes)- Return type:
JWT¶
- class quantum_safe.protocols.jwt.JWTSigner(keypair, hedged=True, issuer=None, backend='auto')[source]¶
Bases:
objectSigns JWTs using PQC or hybrid signature algorithms.
- Parameters:
keypair (
KeyPair) – The signing keypair. Algorithm is inferred from the key.hedged (
bool) – Use hedged signing mode (default True). See module docstring.issuer (
str|None) – Optional issuer string to embed in tokens as the iss claim.backend (
str) – Signature backend: “auto”, “liboqs”, “rustcrypto”.
Example:
signer = JWTSigner(keypair, issuer="auth.myapp.com") token = signer.sign({"sub": "user123", "role": "admin"}) # → "eyJhbGci..." verifier = JWTVerifier(public_key) claims = verifier.verify(token) # → {"sub": "user123", "role": "admin", "iss": "auth.myapp.com", ...}
- sign(claims, expires_in=3600, context=b'jwt')[source]¶
Sign a claims dict and return a JWT string.
- Parameters:
claims (
dict[str,Any]) – Dict of JWT claims. Standard claims (iss, iat, exp) are added automatically.expires_in (
int) – Token lifetime in seconds. Default 1 hour. Pass 0 to omit exp (not recommended).context (
bytes) – Signing context for domain separation. Default b”jwt” — override to prevent cross-purpose reuse.
- Return type:
- Returns:
JWT string in the form “header.payload.signature”.
- class quantum_safe.protocols.jwt.JWTVerifier(public_key, issuer=None, audience=None, backend='auto')[source]¶
Bases:
objectVerifies PQC/hybrid JWTs.
- Parameters:
Example:
verifier = JWTVerifier(public_key, issuer="auth.myapp.com") claims = verifier.verify(token) user_id = claims["sub"]
- verify(token, context=b'jwt', validate_exp=True, validate_nbf=True)[source]¶
Verify a JWT and return its claims.
- Parameters:
- Return type:
- Returns:
Verified claims dict.
- Raises:
VerificationError – If the signature is invalid or claims fail.
ValueError – If the token is structurally malformed.
TLS¶
- class quantum_safe.protocols.tls.HybridTLSConfig(kem_algorithm='X25519+ML-KEM-768', fallback_classical=True, require_hybrid=False, min_tls_version=TLSVersion.TLSv1_3, oqs_provider_path=None)[source]¶
Bases:
objectConfiguration for hybrid TLS key exchange.
- kem_algorithm¶
The hybrid KEM algorithm to request. Default: “X25519+ML-KEM-768”.
- fallback_classical¶
If True (default), include classical X25519 as a fallback group. This allows handshaking with peers that don’t support hybrid.
- require_hybrid¶
If True, reject connections from peers that don’t support hybrid key exchange. Default False — too disruptive for most deployments today.
- min_tls_version¶
Minimum TLS version. Default TLS 1.3 — never negotiate lower.
- oqs_provider_path¶
Path to OQS OpenSSL provider .so/.dylib. If None, we search standard provider locations.
- Parameters:
- quantum_safe.protocols.tls.configure_hybrid_context(ctx, config=None)[source]¶
Configure an ssl.SSLContext for hybrid key exchange.
This modifies the context in-place and also returns it for chaining.
- Parameters:
ctx (
SSLContext) – An ssl.SSLContext to configure. You create this with ssl.create_default_context() or ssl.SSLContext().config (
HybridTLSConfig|None) – HybridTLSConfig. If None, uses default (X25519+ML-KEM-768 with X25519 fallback).
- Return type:
- Returns:
The modified ssl.SSLContext.
- Raises:
ssl.SSLError – if the requested groups aren’t supported by the installed OpenSSL.
Example:
import ssl from quantum_safe.protocols.tls import configure_hybrid_context ctx = ssl.create_default_context() configure_hybrid_context(ctx) # ctx now prefers X25519MLKEM768 with X25519 fallback
X.509¶
- class quantum_safe.protocols.x509.HybridCertificateBuilder(subject_cn, classical_private_key, pqc_keypair, validity_days=365, is_ca=False, dns_names=<factory>, ip_addresses=<factory>, organization='', country='', issuer_cert=None, issuer_key=None, extended_key_usage=<factory>)[source]¶
Bases:
objectBuilder for hybrid X.509 certificates.
Usage:
from quantum_safe.protocols.x509 import HybridCertificateBuilder from quantum_safe.signatures.hybrid import HybridSign # Generate key material signer = HybridSign() hybrid_kp = signer.generate_keypair() classical_priv = Ed25519PrivateKey.generate() builder = HybridCertificateBuilder( subject_cn="service.internal", classical_private_key=classical_priv, pqc_keypair=hybrid_kp, validity_days=365, ) cert_pem, cosig_bundle = builder.build()
- Parameters:
- build(signer=None)[source]¶
Build the hybrid certificate.
- Return type:
- Returns:
(cert_pem, cosig_bundle) –
- cert_pem: PEM-encoded X.509 certificate with embedded
PQC public key extension. Valid to classical verifiers.
- cosig_bundle: CBOR-encoded co-signature bundle:
{pqc_sig: bytes, pqc_algo: str, cert_fp: str} Verifiers that support hybrid validation check this alongside the certificate.
- Parameters:
signer (
object)
- static verify_cosig(cert_pem, cosig_bundle, pqc_public_key)[source]¶
Verify a hybrid certificate’s PQC co-signature.
- Parameters:
- Raises:
VerificationError – if the co-signature is invalid.
KeyParseError – if the bundle is malformed.
- Return type: