EncryptedData
EncryptedData implements RFC 5652 §8 — symmetric content encryption using a shared key.
Unlike EnvelopedData, there is no per-recipient key transport; the caller provides the
symmetric key directly.
Encryption and decryption require the openssl Cargo feature (maturin develop --features openssl).
Class
class EncryptedData:
@staticmethod
def from_der(data: bytes) -> EncryptedData: ...
# Parse a DER- or BER-encoded EncryptedData SEQUENCE.
# Raises ValueError if the outer SEQUENCE envelope is malformed.
@staticmethod
def create(
plaintext: bytes,
key: bytes,
algorithm_oid: ObjectIdentifier | str,
content_type_oid: ObjectIdentifier | str | None = None,
) -> EncryptedData: ...
# Encrypt plaintext under key using the cipher identified by algorithm_oid.
# A fresh random IV is generated for every call.
# content_type_oid defaults to ID_DATA (1.2.840.113549.1.7.1).
# Raises NotImplementedError if built without the openssl Cargo feature.
def decrypt(self, key: bytes) -> bytes: ...
# Recover plaintext. Raises ValueError on key-length mismatch.
# Raises NotImplementedError if built without the openssl Cargo feature.
def to_der(self) -> bytes: ...
version: int # always 0
content_type: ObjectIdentifier # e.g. ID_DATA
content_encryption_algorithm_oid: ObjectIdentifier
content_encryption_algorithm_params: bytes | None
# For CBC ciphers: DER OCTET STRING (04 <len> <iv>) carrying the 16-byte IV.
encrypted_content: bytes | None
unprotected_attrs: bytes | None
Usage
from synta.cms import EncryptedData, ID_AES128_CBC, ID_AES256_CBC
KEY_128 = bytes.fromhex("00112233445566778899aabbccddeeff")
KEY_256 = bytes(range(32))
# ── Encrypt ───────────────────────────────────────────────────────────────────
plaintext = b"Confidential payload."
ed = EncryptedData.create(plaintext, KEY_128, ID_AES128_CBC)
# Inspect fields
print(ed.version) # 0
print(ed.content_type) # 1.2.840.113549.1.7.1 (id-data)
print(ed.content_encryption_algorithm_oid) # 2.16.840.1.101.3.4.1.2
iv = ed.content_encryption_algorithm_params[2:] # strip 04 <len> header
print(iv.hex()) # 16-byte random IV
# ── Round-trip ────────────────────────────────────────────────────────────────
assert EncryptedData.from_der(ed.to_der()).decrypt(KEY_128) == plaintext
# ── Re-encrypt with replaced content ─────────────────────────────────────────
decrypted = ed.decrypt(KEY_128)
modified = decrypted.replace(b"PENDING", b"APPROVED")
ed2 = EncryptedData.create(modified, KEY_256, ID_AES256_CBC)
assert ed2.decrypt(KEY_256) == modified
Each create call generates a fresh random IV; two calls on the same plaintext produce
different ciphertext. See examples/example_cms_encrypted_data.py for a full example
including openssl enc interop in both directions.
See also EnvelopedData for per-recipient key transport and CMS Overview for all content types.