synta 0.1.6

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# CMS-KEM Types


`synta.kem` provides `KEMRecipientInfo` and `CMSORIforKEMOtherInfo` for RFC 9629
quantum-safe KEM recipient structures, along with ML-KEM (FIPS 203) OID constants.

`KEMRecipientInfo` is carried as an `OtherRecipientInfo` alternative identified by
`id-ori-kem` (`1.2.840.113549.1.9.16.13.3`).

```python
import synta.kem as kem
```

These types are also re-exported from `synta.cms`.

## KEMRecipientInfo

RFC 9629 §5 recipient structure for KEM-based key transport.

```python
class KEMRecipientInfo:
    @staticmethod
    def from_der(data: bytes) -> KEMRecipientInfo: ...
    def to_der(self) -> bytes: ...

    version: int                             # always 0
    recipient_id: bytes                      # raw RecipientIdentifier CHOICE TLV
    kem_algorithm_oid: ObjectIdentifier      # KEM algorithm (e.g. ML-KEM-768)
    kem_algorithm_params: bytes | None
    kem_ciphertext: bytes                    # KEM ciphertext (kemct field)
    kdf_algorithm_oid: ObjectIdentifier      # key-derivation algorithm
    kdf_algorithm_params: bytes | None
    kek_length: int                          # KEK length in bytes (1–65535)
    ukm: bytes | None                        # user keying material
    key_encryption_algorithm_oid: ObjectIdentifier  # key-wrap algorithm
    key_encryption_algorithm_params: bytes | None
    encrypted_key: bytes                     # encrypted content-encryption key
```

## CMSORIforKEMOtherInfo

RFC 9629 §5.3 — `otherInfo` input to the KDF when deriving a KEK from a KEM shared secret.

```python
class CMSORIforKEMOtherInfo:
    @staticmethod
    def from_der(data: bytes) -> CMSORIforKEMOtherInfo: ...
    def to_der(self) -> bytes: ...

    key_encryption_algorithm_oid: ObjectIdentifier
    key_encryption_algorithm_params: bytes | None
    kek_length: int
    ukm: bytes | None
```

## OID constants

### ML-KEM OIDs (FIPS 203)

| Constant | OID | Description |
|---|---|---|
| `ID_ML_KEM_512` | `2.16.840.1.101.3.4.4.1` | ML-KEM-512 key encapsulation |
| `ID_ML_KEM_768` | `2.16.840.1.101.3.4.4.2` | ML-KEM-768 key encapsulation |
| `ID_ML_KEM_1024` | `2.16.840.1.101.3.4.4.3` | ML-KEM-1024 key encapsulation |

### CMS OtherRecipientInfo OIDs (RFC 9629 §6.2)

| Constant | OID | Description |
|---|---|---|
| `ID_ORI` | `1.2.840.113549.1.9.16.13` | Root arc for OtherRecipientInfo alternatives |
| `ID_ORI_KEM` | `1.2.840.113549.1.9.16.13.3` | Identifies a `KEMRecipientInfo` |

## Usage

```python
import synta
import synta.kem as kem

# Parse a KEMRecipientInfo from an OtherRecipientInfo body
kri = kem.KEMRecipientInfo.from_der(ori_body_der)
print(f"KEM algorithm: {kri.kem_algorithm_oid}")
print(f"KDF algorithm: {kri.kdf_algorithm_oid}")
print(f"KEK length:    {kri.kek_length}")
print(f"ciphertext:    {kri.kem_ciphertext.hex()}")

# Check if this is an ML-KEM-768 recipient
if kri.kem_algorithm_oid == kem.ID_ML_KEM_768:
    # Decapsulate with a PrivateKey
    priv_key = synta.PrivateKey.from_der(kem_priv_der)
    shared_secret = priv_key.kem_decapsulate(kri.kem_ciphertext)
    # Then apply KDF (kri.kdf_algorithm_oid) over shared_secret + kri.ukm to derive KEK
```

See also [Keys](../pki/keys.md) for `PublicKey.kem_encapsulate()` and
`PrivateKey.kem_decapsulate()`, and [CMS Overview](overview.md) for the full module import.