Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

EnvelopedData

EnvelopedData implements RFC 5652 §6 — encrypted content with per-recipient key transport. The content-encryption key (CEK) is encrypted under each recipient’s public key and carried in RecipientInfo structures. The content itself is encrypted using a symmetric cipher.

Decryption and encryption require the openssl Cargo feature.

EnvelopedData

class EnvelopedData:
    @staticmethod
    def from_der(data: bytes) -> EnvelopedData: ...
    def to_der(self) -> bytes: ...

    def decrypt(self, private_key: PrivateKey) -> bytes: ...
    # Decrypt using the recipient's private key.
    # Raises ValueError if no matching RecipientInfo is found or decryption fails.
    # Requires the openssl Cargo feature.

    version: int
    originator_info: bytes | None
    recipient_infos: bytes           # raw RecipientInfos SET bytes
    content_type: ObjectIdentifier
    content_encryption_algorithm_oid: ObjectIdentifier
    content_encryption_algorithm_params: bytes | None
    encrypted_content: bytes | None
    unprotected_attrs: bytes | None

EnvelopedDataBuilder

Fluent builder for EnvelopedData (RFC 5652 §6). Requires the openssl Cargo feature.

class EnvelopedDataBuilder:
    def __init__(
        self,
        plaintext: bytes,
        recipients: list[tuple[Certificate | bytes, ObjectIdentifier]],
        *,
        content_enc_alg: ObjectIdentifier | None = None,
    ) -> None: ...
    # recipients: list of (cert, key_wrap_oid) tuples.
    # cert may be a Certificate object or DER bytes.
    # key_wrap_oid: ID_RSAES_OAEP (recommended) or ID_RSA_ENCRYPTION (legacy).
    # content_enc_alg defaults to id-aes256-CBC.

    def add_originator_cert(self, cert: Certificate | bytes) -> EnvelopedDataBuilder: ...
    def add_originator_crl(self, crl: CertificateList | bytes) -> EnvelopedDataBuilder: ...
    def set_unprotected_attrs(self, attrs: bytes) -> EnvelopedDataBuilder: ...
    def build(self) -> EnvelopedData: ...

Usage

import synta
from synta.cms import EnvelopedData, EnvelopedDataBuilder, ID_RSAES_OAEP, ID_AES256_CBC

# Encrypt for one recipient
recipient_cert = synta.Certificate.from_der(open("recipient.der", "rb").read())
plaintext = b"Confidential message."

ed = EnvelopedDataBuilder(
    plaintext,
    [(recipient_cert, ID_RSAES_OAEP)],
    content_enc_alg=ID_AES256_CBC,
).build()
ciphertext_der = ed.to_der()

# Decrypt
priv_key = synta.PrivateKey.from_pem(open("recipient.pem", "rb").read())
ed2 = EnvelopedData.from_der(ciphertext_der)
recovered = ed2.decrypt(priv_key)
assert recovered == plaintext

See also EncryptedData for shared-key symmetric encryption and CMS-KEM for quantum-safe KEM recipient structures.