synta 0.2.3

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# 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

```python
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.

```python
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

```python
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](encrypted-data.md) for shared-key symmetric encryption and
[CMS-KEM](kem.md) for quantum-safe KEM recipient structures.