### Complete KEM Key Workflow Example Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-key.md Demonstrates a full workflow including cipher suite setup, key pair generation from a seed, accessing key components, and loading keys from JWK and PEM formats. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey # Create cipher suite suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Generate key pair using KEM key_pair = suite.kem.derive_key_pair(b"deterministic_seed") # Access components private_key = key_pair.private_key public_key = key_pair.public_key # Load keys from different formats pk_from_jwk = KEMKey.from_jwk({"kty": "EC", "crv": "P-256", "x": "...", "y": "..."}) pk_from_pem = KEMKey.from_pem(b"-----BEGIN PUBLIC KEY-----\n...") ``` -------------------------------- ### Install PyHPKE Source: https://github.com/dajiaji/pyhpke/blob/main/docs/index.md Install the PyHPKE library using pip. This is the first step to using the library. ```console pip install pyhpke ``` -------------------------------- ### Install PyHPKE Source: https://github.com/dajiaji/pyhpke/blob/main/README.md Install the PyHPKE library using pip. This is the first step before using the library in your Python projects. ```sh $ pip install pyhpke ``` -------------------------------- ### Complete Workflow Example Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-key.md Demonstrates a complete workflow involving cipher suite creation, key pair generation, and accessing key components. ```APIDOC ## Example: Complete Workflow ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey # Create cipher suite suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Generate key pair using KEM key_pair = suite.kem.derive_key_pair(b"deterministic_seed") # Access components private_key = key_pair.private_key public_key = key_pair.public_key # Load keys from different formats pk_from_jwk = KEMKey.from_jwk({"kty": "EC", "crv": "P-256", "x": "...", "y": "..."}) pk_from_pem = KEMKey.from_pem(b"-----BEGIN PUBLIC KEY-----\n...") ``` ``` -------------------------------- ### CipherSuite Initialization with KEMId Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md Example of initializing a CipherSuite using a specific KEMId. Ensure the KDFId and AEADId are compatible with the chosen KEM. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new(KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM) ``` -------------------------------- ### CipherSuite Initialization with KDFId Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md Example of initializing a CipherSuite using a specific KDFId. Ensure the KEMId and AEADId are compatible with the chosen KDF. ```python from pyhpke import KDFId, CipherSuite, KEMId, AEADId suite = CipherSuite.new(KEMId.DHKEM_X25519_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM) ``` -------------------------------- ### Python KEM Encap Example Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-interface.md Example demonstrating how to use the encap method to encapsulate a shared secret. This includes setting up the CipherSuite, loading the recipient's public key, and optionally providing the sender's private key for authenticated mode. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Load recipient's public key pkr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) # Encapsulate (for authenticated mode with sender's private key) sks = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "...", "y": "...", "d": "..." }) shared_secret, enc = suite.kem.encap(pkr, sks=sks) ``` -------------------------------- ### Create CipherSuite with AES128_GCM Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiate a CipherSuite using specific KEM, KDF, and AEAD algorithms. This example configures for AES128_GCM. ```python suite_aes = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ``` -------------------------------- ### Create CipherSuite with Standard Identifiers Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md This example demonstrates how to create a CipherSuite instance using the `CipherSuite.new()` factory method with specific identifiers for KEM (DHKEM_P256_HKDF_SHA256), KDF (HKDF_SHA256), and AEAD (AES128_GCM). ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId # Create a suite with P-256 elliptic curve, HKDF-SHA256, and AES-128-GCM suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ``` -------------------------------- ### Run Tests with Tox Source: https://github.com/dajiaji/pyhpke/blob/main/README.md Execute the project's test suite using the Tox testing framework. Ensure Tox is installed and the project is cloned before running. ```sh $ tox ``` -------------------------------- ### Configuration Guide Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/INDEX.txt Guidance on configuring HPKE cipher suites, context parameters, and algorithm selection, including best practices and common patterns. ```APIDOC ## Configuration Guide ### Description This guide explains how to configure and select cryptographic algorithms and parameters when using the PyHPKE library, ensuring optimal security and performance. ### Cipher Suite Selection - Patterns and recommendations for choosing appropriate KEM, KDF, and AEAD algorithms based on security requirements. ### Context Creation Configuration - Details on parameters required for creating sender, recipient, and exporter contexts. ### Message Encryption Parameters - Configuration options related to encrypting messages, such as nonce generation and associated data. ### Algorithm Selection - A guide to understanding the trade-offs between different supported algorithms. ### Best Practices - Recommendations for secure configuration and usage, including immutability and environment considerations. ``` -------------------------------- ### Setup Cipher Suite and Load Keys Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/README.md Initializes the cipher suite with specified cryptographic algorithms and loads the recipient's public key from JWK format. Ensure the JWK contains valid 'kty', 'crv', 'x', and 'y' parameters. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey # Create cipher suite suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Load recipient's public key pkr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) ``` -------------------------------- ### JWK Public Key Example Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md An example of a public JWK dictionary for an Elliptic Curve key. ```python public_jwk = { "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", } ``` -------------------------------- ### JWK Private Key Example Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md An example of a private JWK dictionary, extending a public JWK with the private key component 'd'. ```python private_jwk = { **public_jwk, "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", } ``` -------------------------------- ### Example: Recipient Context and Decryption Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md Demonstrates setting up a `CipherSuite` with specific cryptographic parameters, loading a recipient's private key from JWK format, creating a recipient context, and decrypting a message. The `enc` and `ciphertext` variables must be defined prior to this code. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Load recipient's private key skr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", }) # Create recipient context recipient = suite.create_recipient_context(enc, skr) # Decrypt message plaintext = recipient.open(ciphertext) assert plaintext == b"Hello, recipient!" ``` -------------------------------- ### Create Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/README.md Instantiate a CipherSuite object by specifying the KEM, KDF, and AEAD algorithm identifiers. Refer to the Configuration guide for recommended algorithm combinations. ```python suite = CipherSuite.new(kem_id, kdf_id, aead_id) ``` -------------------------------- ### Create sender context for encryption (Base mode) Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md Shows how to create a sender context for encryption using a recipient's public key. This example uses the Base HPKE mode, which does not involve pre-shared keys or sender's private keys. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Load recipient's public key pkr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) # Create sender context (Base mode) enc, sender = suite.create_sender_context(pkr) # Encrypt message ciphertext = sender.seal(b"Hello, recipient!") ``` -------------------------------- ### HPKE Encryption and Decryption Example Source: https://github.com/dajiaji/pyhpke/blob/main/README.md Demonstrates a full HPKE encryption and decryption cycle. The sender encrypts a message using the recipient's public key, and the recipient decrypts it using their private key. Ensure correct cipher suite and key parameters are used. ```python from pyhpke import AEADId, CipherSuite, KDFId, KEMId, KEMKey # The sender side: suite_s = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) pkr = KEMKey.from_jwk( # from_pem is also available. { "kid": "01", "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", } ) enc, sender = suite_s.create_sender_context(pkr) ct = sender.seal(b"Hello world!") # The recipient side: suite_r = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) skr = KEMKey.from_jwk( { "kid": "01", "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", } ) recipient = suite_r.create_recipient_context(enc, skr) pt = recipient.open(ct) assert pt == b"Hello world!" ``` -------------------------------- ### Initialize CipherSuite and access KEM context Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md Demonstrates how to initialize a CipherSuite with specific cryptographic algorithms and access its KEM context to derive a key pair. ```python suite = CipherSuite.new( KEMId.DHKEM_X25519_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM ) kem_context = suite.kem key_pair = kem_context.derive_key_pair(b"seed_bytes") ``` -------------------------------- ### CipherSuite Initialization with AEADId Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md Demonstrates initializing a CipherSuite with different AEADIds, including AES-256-GCM for encryption and AEADId.EXPORT_ONLY for key derivation purposes only. ```python from pyhpke import AEADId, CipherSuite, KEMId, KDFId # Use AES-256-GCM suite = CipherSuite.new(KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM) # Use export-only mode for key derivation only export_suite = CipherSuite.new(KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.EXPORT_ONLY) ``` -------------------------------- ### Get KEM Identifier Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-interface.md Access the KEM identifier from a CipherSuite instance. This property returns a KEMId enum value. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_X25519_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) assert suite.kem.id == KEMId.DHKEM_X25519_HKDF_SHA256 ``` -------------------------------- ### Get AEAD Identifier Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/aead-interface.md Access the AEAD identifier using the `id` property. This is typically done through the `CipherSuite.aead` attribute. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM ) assert suite.aead.id == AEADId.AES256_GCM ``` -------------------------------- ### Get KDF Identifier Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kdf-interface.md Retrieve the identifier for the configured Key Derivation Function (KDF). This is useful for verifying the KDF algorithm being used. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) assert suite.kdf.id == KDFId.HKDF_SHA256 ``` -------------------------------- ### KEMKeyPair Class Definition Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/types.md Defines the KEMKeyPair container for public and private key pairs. Used in key creation and context setup. ```python class KEMKeyPair: def __init__(self, sk: KEMKeyInterface, pk: KEMKeyInterface) -> None @property def private_key(self) -> KEMKeyInterface @property def public_key(self) -> KEMKeyInterface ``` -------------------------------- ### CipherSuite.new() Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md Factory method to create a cipher suite from standard identifiers. This is the recommended way to instantiate a CipherSuite. ```APIDOC ## CipherSuite.new(kem_id, kdf_id, aead_id) ### Description Factory method to create a cipher suite from standard identifiers. ### Method `classmethod` ### Parameters #### Path Parameters - **kem_id** (KEMId) - Required - KEM identifier (e.g., `KEMId.DHKEM_P256_HKDF_SHA256`) - **kdf_id** (KDFId) - Required - KDF identifier (e.g., `KDFId.HKDF_SHA256`) - **aead_id** (AEADId) - Required - AEAD identifier (e.g., `AEADId.AES128_GCM`) ### Returns `CipherSuite` instance configured with the specified algorithms ### Raises `ValueError` if an unsupported KEM, KDF, or AEAD identifier is provided ### Request Example ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId # Create a suite with P-256 elliptic curve, HKDF-SHA256, and AES-128-GCM suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ``` ``` -------------------------------- ### Create CipherSuite with CHACHA20_POLY1305 Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Demonstrates creating a new CipherSuite instance to switch to a different AEAD algorithm, CHACHA20_POLY1305. The original suite remains unchanged due to immutability. ```python # To use different AEAD, create new suite suite_chacha = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.CHACHA20_POLY1305 ) # Original suite_aes is unchanged ``` -------------------------------- ### Get AEAD Key Size Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/aead-interface.md Retrieve the required key size in bytes for the AEAD algorithm using the `key_size` property. This property is accessed via the `CipherSuite.aead` attribute. ```python suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) assert suite.aead.key_size == 16 # 128 bits = 16 bytes ``` -------------------------------- ### Create HPKE Sender Context with PSK Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Demonstrates creating a sender context using a pre-shared key (PSK). A new context must be created if PSK is not intended for subsequent operations. ```python # Create sender context with PSK enc, sender = suite.create_sender_context(pkr, psk=b"secret") # To encrypt without PSK, create new context with different parameters enc2, sender2 = suite.create_sender_context(pkr) # No PSK ``` -------------------------------- ### Get AEAD Nonce Size Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/aead-interface.md Obtain the required nonce size in bytes for the AEAD algorithm using the `nonce_size` property. Nonces are managed by context objects and derived from a base nonce and sequence number for each encryption. ```python suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM ) assert suite.aead.nonce_size == 12 ``` -------------------------------- ### Create Standard Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiates a CipherSuite with the common P-256, HKDF-SHA256, and AES128-GCM algorithms for 128-bit security. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ``` -------------------------------- ### Create Performance-Optimized Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiates a CipherSuite using X25519, HKDF-SHA256, and ChaCha20-Poly1305 for high performance. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_X25519_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.CHACHA20_POLY1305 ) ``` -------------------------------- ### Get AEAD Tag Size Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/aead-interface.md Retrieves the authentication tag size in bytes for the current AEAD cipher suite. The tag is appended to ciphertexts and verified during decryption. A standard size of 16 bytes is common for authenticated modes. ```python suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.CHACHA20_POLY1305 ) assert suite.aead.tag_size == 16 ``` -------------------------------- ### KEMKeyPair Constructor Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-key.md Initializes a KEMKeyPair object with separate private and public keys. Both keys must conform to the KEMKeyInterface. ```python def __init__(self, sk: KEMKeyInterface, pk: KEMKeyInterface) -> None: ``` -------------------------------- ### Encryption Workflow Steps Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/module-overview.md Illustrates the sequence of operations for encrypting data. This includes creating a cipher suite, loading keys, establishing a sender context, and sealing messages. ```plaintext 1. Create cipher suite CipherSuite.new(KEMId.*, KDFId.*, AEADId.*) 2. Load/derive keys KEMKey.from_jwk() / from_pem() / from_pyca_cryptography_key() 3. Create sender context enc, sender = suite.create_sender_context(pkr, info, psk, sks, ...) Internally: - KEM.encap(pkr, sks, eks) → (shared_secret, enc) - CipherSuite._key_schedule(...) → KDF operations - labeled_extract(b"", b"psk_id_hash", psk_id) - labeled_extract(b"", b"info_hash", info) - labeled_extract(shared_secret, b"secret", psk) - labeled_expand() for key, base_nonce, exporter_secret - Create SenderContext with AEAD key 4. Encrypt messages ct = sender.seal(plaintext, aad) Internally: - AEAD.seal(plaintext, nonce, aad) - Nonce = base_nonce XOR seq_number - Increment sequence number 5. Send to recipient: - Transmit: (enc, ct, aad) ``` -------------------------------- ### KEMKeyPair Constructor Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-key.md Creates a key pair from separate public and private keys. ```APIDOC ## Constructor: KEMKeyPair ### `KEMKeyPair(sk, pk)` Creates a key pair from separate public and private keys. ```python def __init__(self, sk: KEMKeyInterface, pk: KEMKeyInterface) -> None ``` **Parameters** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | sk | KEMKeyInterface | Yes | Private key | | pk | KEMKeyInterface | Yes | Public key | **Returns**: `KEMKeyPair` instance ``` -------------------------------- ### Create Legacy Compatibility Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiates a CipherSuite with P-384, HKDF-SHA384, and AES256-GCM for systems requiring 384-bit curves. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P384_HKDF_SHA384, KDFId.HKDF_SHA384, AEADId.AES256_GCM ) ``` -------------------------------- ### Extract and Expand Keying Material (Python) Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kdf-interface.md Performs a combined extract-then-expand operation for input keying material (ikm). This is more convenient than separate `extract()` and `expand()` calls for one-shot operations. Typically not called directly; HPKE uses `labeled_extract()` and `labeled_expand()`. ```python suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ikm = b"input_keying_material" salt = b"salt" info = b"context" key = suite.kdf.extract_and_expand(salt, ikm, info, 32) assert len(key) == 32 ``` -------------------------------- ### Using Export-Only AEAD for Key Derivation Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/aead-interface.md Demonstrates how to set up and use the Export-Only AEAD mode for deriving keys. This mode disables encryption and only allows key export operations. It's useful for testing KEM and KDF functionality without actual encryption. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey # Export-only suite for key derivation suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.EXPORT_ONLY ) pkr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) enc, exporter = suite.create_sender_context(pkr) # Can only use export derived_key = exporter.export(b"derived_key", 32) # This would raise NotSupportedError: # exporter.seal(b"message") ``` -------------------------------- ### extract_and_expand(salt, ikm, info, length) Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kdf-interface.md Performs a combined extract-then-expand operation, deriving key material from input keying material (IKM) using a salt and application context. This is a convenience method for sequential HKDF operations. ```APIDOC ## extract_and_expand(salt, ikm, info, length) ### Description Combined extract-then-expand operation. ### Method Signature `extract_and_expand(self, salt: bytes, ikm: bytes, info: bytes, length: int) -> bytes` ### Parameters #### Path Parameters - **salt** (bytes) - Required - Salt value - **ikm** (bytes) - Required - Input keying material - **info** (bytes) - Required - Application context information - **length** (int) - Required - Desired output length ### Returns - **bytes** derived key material ### Raises - **ValueError** if requested length exceeds maximum ### Notes - Equivalent to calling `extract()` then `expand()` in sequence. - More convenient than separate calls for one-shot operations. - Typically not called directly; HPKE uses `labeled_extract()` and `labeled_expand()`. ### Example ```python suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) ikm = b"input_keying_material" salt = b"salt" info = b"context" key = suite.kdf.extract_and_expand(salt, ikm, info, 32) assert len(key) == 32 ``` ``` -------------------------------- ### SenderContext open method signature Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/context-interfaces.md The open method is not available on SenderContext. Attempting to use it will raise a NotSupportedError. ```python def open(self, ct: bytes, aad: bytes = b"") -> bytes ``` -------------------------------- ### Create High-Security Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiates a CipherSuite with P-521, HKDF-SHA512, and AES256-GCM for maximum 256-bit security. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P521_HKDF_SHA512, KDFId.HKDF_SHA512, AEADId.AES256_GCM ) ``` -------------------------------- ### CipherSuite Factory Method Signature Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md The `new` class method provides a factory for creating CipherSuite instances using standard KEM, KDF, and AEAD identifiers. It simplifies the process of setting up a cipher suite with common cryptographic algorithms. ```python @classmethod def new(cls, kem_id: KEMId, kdf_id: KDFId, aead_id: AEADId) -> CipherSuite: ``` -------------------------------- ### Full Encryption/Decryption Workflow Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/context-interfaces.md Demonstrates a complete encryption and decryption process using sender and recipient contexts. Ensure the CipherSuite, keys, and info are consistent between sender and recipient for successful operation. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId, KEMKey # Setup suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) # Recipient's keys pkr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) skr = KEMKey.from_jwk({ "kty": "EC", "crv": "P-256", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", }) # === SENDER SIDE === enc, sender = suite.create_sender_context(pkr, info=b"application context") # Encrypt messages message_1 = b"First message" ct_1 = sender.seal(message_1) message_2 = b"Second message" aad = b"metadata for message 2" ct_2 = sender.seal(message_2, aad=aad) # Derive shared secret shared_secret = sender.export(b"shared_secret", 32) # === RECIPIENT SIDE === # Create context using same parameters recipient = suite.create_recipient_context(enc, skr, info=b"application context") # Decrypt messages pt_1 = recipient.open(ct_1) assert pt_1 == message_1 pt_2 = recipient.open(ct_2, aad=aad) assert pt_2 == message_2 # Derive same shared secret shared_secret_derived = recipient.export(b"shared_secret", 32) assert shared_secret == shared_secret_derived ``` -------------------------------- ### KEMKey and KEMKeyPair Classes Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/module-overview.md Classes for managing KEM keys, including factory methods for creating keys from various formats and a container for key pairs. ```APIDOC ## KEMKey and KEMKeyPair ### Description Provides key factory/builder classes for KEM operations. `KEMKey` allows creating keys from different formats, and `KEMKeyPair` holds public and private key pairs. ### KEMKey Class - **Purpose**: Factory for creating KEM keys. - **Methods**: - `from_jwk(data)`: Creates a `KEMKey` from a JSON Web Key (JWK) formatted string or dictionary. - `from_pem(data)`: Creates a `KEMKey` from a PEM-encoded string. - `from_pyca_cryptography_key(k)`: Creates a `KEMKey` from a `cryptography` library key object. ### KEMKeyPair Class - **Purpose**: Container for a public and private key pair. - **Properties**: - `private_key`: The private key component. - `public_key`: The public key component. ### Supported Key Types - EC: P-256, P-384, P-521 (via `ECKey`) - X25519 (via `X25519Key`) - X448 (via `X448Key`) ``` -------------------------------- ### CipherSuite Constructor Signature Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/cipher-suite.md The constructor for the CipherSuite class requires explicit implementations of KEM, KDF, and AEAD interfaces. This method is typically not called directly; use `CipherSuite.new()` instead. ```python def __init__(self, kem: KEMInterface, kdf: KDFInterface, aead: AEADInterface) -> None: ``` -------------------------------- ### Key Export Configuration Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Derive additional keying material from a context using the `export()` method. The `exporter_context` should be a unique application-specific label for each derived key. ```python derived_key = context.export( exporter_context, # bytes: Context string length # int: Bytes to derive ) ``` -------------------------------- ### Create Export-Only Cipher Suite Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/configuration.md Instantiates a CipherSuite for key derivation only, without message encryption, using P-256 and HKDF-SHA256. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.EXPORT_ONLY ) ``` -------------------------------- ### Expand Pseudorandom Key (Python) Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kdf-interface.md Expands a pseudorandom key (prk) into output keying material (OKM) of a specified length using application context information. Typically not called directly; use `labeled_expand()` instead. The `info` parameter should be unique for different output purposes. ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) prk = b"pseudorandom_key_32_bytes" + b'\x00' info = b"application_context" # Expand to 16 bytes okm = suite.kdf.expand(prk, info, 16) assert len(okm) == 16 ``` -------------------------------- ### Create KEMKey from PEM Data Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kem-key.md Use this method to load a public or private HPKE key from PEM-encoded data. Supports PKCS#8 and SEC1 formats. Raises ValueError if decoding fails or the key type is unsupported. ```python from pyhpke import KEMKey # Load public key from PEM public_pem = b"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\nZe2loSV3wrroKUN/4zhwGhCqo3Xhu1td4QjeQ5wIVR0HlLtdXARY/f55A3fnzQbPcm6hgr34Mp8p+nuzQCE0Zw==\n-----END PUBLIC KEY-----" pkr = KEMKey.from_pem(public_pem) # Load private key from PEM (as string) private_pem_str = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgr/kHyZ+a06rmxM3yESK84r1otSg+aQcVStkRhA+iCM+hRANCAARjblWhJXfCuugoQ3/jOHAaEKqjdeG7W13hCN5DnAhVHQeUu11cBFj9/nkDd+fNBs9ybqGCvfwynyn6e7NAARRh\n-----END PRIVATE KEY-----" skr = KEMKey.from_pem(private_pem_str) ``` -------------------------------- ### Context Methods Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/module-overview.md Methods available on encryption contexts for sealing (encrypting), opening (decrypting), and exporting keying material. ```APIDOC ## Context Methods ### Description Provides methods for performing encryption, decryption, and key export operations within HPKE contexts. ### Methods - `seal(pt, aad)`: Encrypts plaintext (`pt`) with optional authenticated additional data (`aad`). Available on `SenderContext`. - `open(ct, aad)`: Decrypts ciphertext (`ct`) with optional authenticated additional data (`aad`). Available on `RecipientContext`. - `export(context, length)`: Derives keying material of a specified `length` from the context. Available on `ExporterContext`, `SenderContext`, and `RecipientContext`. ``` -------------------------------- ### Types and Interfaces Reference Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/INDEX.txt Reference for all public types, including enumerations for KEM, KDF, AEAD, and Mode, as well as interface and container classes. ```APIDOC ## Types and Interfaces Reference ### Description This section provides a comprehensive reference for all public types, enumerations, interfaces, and container classes used within the PyHPKE library. ### Enumerations - **KEMId**: Identifiers for supported Key Encapsulation Mechanisms. - **KDFId**: Identifiers for supported Key Derivation Functions. - **AEADId**: Identifiers for supported Authenticated Data Encryption algorithms. - **Mode**: Represents the different HPKE operational modes (Base, PSK, Auth, AuthPSK). ### Interface Classes - Documentation for all public interface classes, including `CipherSuite`, `KEMKey`, `SenderContext`, `RecipientContext`, `ExporterContext`, and others. ### Container Classes - **KEMKeyPair**: A class that holds a pair of KEM public and private keys. ### Type Aliases and Constants - Definitions of type aliases and constants used throughout the library for clarity and consistency. ``` -------------------------------- ### ContextInterface Source: https://github.com/dajiaji/pyhpke/blob/main/docs/api.md The ContextInterface provides methods for sealing, opening, and exporting data within an HPKE context. ```APIDOC ## class pyhpke.ContextInterface ### Methods #### seal(pt: bytes, aad: bytes = b'') -> bytes #### open(ct: bytes, aad: bytes = b'') -> bytes #### export(exporter_context: bytes, length: int) -> bytes ``` -------------------------------- ### labeled_expand Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/api-reference/kdf-interface.md Expands pseudorandom keying material into output keying material using HPKE labeling. It prepends the desired length and HPKE version/suite ID to the label. ```APIDOC ## Method: labeled_expand ### `labeled_expand(prk, label, info, length)` Expands with HPKE labeling as per RFC 9180. ```python def labeled_expand(self, prk: bytes, label: bytes, info: bytes, length: int) -> bytes ``` **Parameters** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | prk | bytes | Yes | Pseudorandom key (typically from `labeled_extract()`) | | label | bytes | Yes | Label string (e.g., `b"key"`, `b"base_nonce"`) | | info | bytes | Yes | Application context information | | length | int | Yes | Desired output length | **Returns**: `bytes` output keying material **Raises**: `ValueError` if requested length exceeds maximum **Notes**: - Automatically prepends length and HPKE version/suite ID to the label - Label format: `length || HPKE-v1 || suite_id || label || info` - Used internally by the cipher suite for all expand operations - Different labels ensure different output even with same PRK **Example**: ```python from pyhpke import CipherSuite, KEMId, KDFId, AEADId suite = CipherSuite.new( KEMId.DHKEM_P256_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES128_GCM ) prk = b"pseudorandom_key" + b'\x00' * 16 context = b"key_schedule_context" # Derive encryption key key = suite.kdf.labeled_expand(prk, b"key", context, 16) assert len(key) == 16 # Derive nonce nonce = suite.kdf.labeled_expand(prk, b"base_nonce", context, 12) assert len(nonce) == 12 ``` ``` -------------------------------- ### Context Interfaces Source: https://github.com/dajiaji/pyhpke/blob/main/_autodocs/INDEX.txt Defines the base `ContextInterface` and its concrete implementations for sender, recipient, and exporter contexts, detailing the encryption, decryption, and key export flows. ```APIDOC ## Context Interfaces ### Description This section details the `ContextInterface` and its derived classes, which manage the cryptographic state for HPKE operations. It covers the interfaces for sending (encryption), receiving (decryption), and exporting keys. ### Base Interface - **ContextInterface**: Abstract base class defining common methods and properties for HPKE contexts. ### Concrete Interfaces - **SenderContext**: Handles the encryption process. Provides methods to encrypt data using the established shared secret. - **RecipientContext**: Handles the decryption process. Provides methods to decrypt ciphertext using the established shared secret. - **ExporterContext**: Handles key export. Provides methods to derive cryptographic keys for other purposes from the established shared secret. ### Key Operations - **Encryption/Decryption Flow**: Describes the sequence of operations for encrypting and decrypting messages. - **Export Method**: Details the parameters and usage for exporting keys. ```