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

PublicKey and PrivateKey

PublicKey and PrivateKey are backend-agnostic key types that wrap OpenSSL keys. They support RSA, EC (NIST curves), EdDSA (Ed25519 / Ed448), ML-DSA (FIPS 204), and ML-KEM (FIPS 203). Both types are exported from the top-level synta package.

PublicKey

Construction

PublicKey.from_pem(data: bytes) -> PublicKey

Load from PEM-encoded SubjectPublicKeyInfo.

PublicKey.from_der(data: bytes) -> PublicKey

Load from DER-encoded SubjectPublicKeyInfo.

PublicKey.from_rsa_components(n: bytes, e: bytes) -> PublicKey

Construct an RSA public key from big-endian modulus n and public exponent e bytes. Raises ValueError if the inputs are not a valid RSA key.

PublicKey.from_ec_components(x: bytes, y: bytes, curve: str) -> PublicKey

Construct an EC public key from affine coordinates x, y and NIST curve name. curve must be "P-256", "P-384", or "P-521". Raises ValueError for unknown curve names or invalid coordinates.

Serialisation

pub_key.to_pem() -> bytes
pub_key.to_der() -> bytes

Properties

PropertyTypeDescription
key_typestrLowercase key algorithm: "rsa", "ec", "ed25519", "ed448", "dsa", "ml-dsa-44", "ml-dsa-65", "ml-dsa-87", "ml-kem-512", "ml-kem-768", "ml-kem-1024", or "unknown"
key_sizeint | NoneKey size in bits, or None for EdDSA and post-quantum keys
modulusbytes | NoneRSA modulus n as big-endian bytes, or None for non-RSA keys
public_exponentbytes | NoneRSA public exponent e as big-endian bytes, or None for non-RSA keys
curve_namestr | NoneNIST curve name for EC keys (e.g. "P-256"), or None
xbytes | NoneEC affine X coordinate as big-endian bytes, or None for non-EC keys
ybytes | NoneEC affine Y coordinate as big-endian bytes, or None for non-EC keys

Methods

pub_key.rsa_oaep_encrypt(plaintext: bytes, hash_algorithm: str = "sha256") -> bytes
pub_key.rsa_pkcs1v15_encrypt(plaintext: bytes) -> bytes
pub_key.kem_encapsulate() -> tuple[bytes, bytes]   # ML-KEM: (ciphertext, shared_secret)
pub_key.verify_signature(
    signature: bytes,
    data: bytes,
    algorithm: str | None = None,
    context: bytes | None = None,
) -> None

Verify a signature over data. Raises ValueError on failure.

  • algorithm: hash name (e.g. "sha256") for RSA and ECDSA. Pass None for Ed25519, Ed448, and ML-DSA keys.
  • context: ML-DSA domain-separation string (FIPS 204); None = empty. Ignored for non-ML-DSA keys.

Full class stub

class PublicKey:
    @staticmethod
    def from_pem(data: bytes) -> PublicKey: ...
    @staticmethod
    def from_der(data: bytes) -> PublicKey: ...
    @staticmethod
    def from_rsa_components(n: bytes, e: bytes) -> PublicKey: ...
    @staticmethod
    def from_ec_components(x: bytes, y: bytes, curve: str) -> PublicKey: ...
    def to_pem(self) -> bytes: ...
    def to_der(self) -> bytes: ...
    key_type: str
    key_size: int | None
    modulus: bytes | None
    public_exponent: bytes | None
    curve_name: str | None
    x: bytes | None
    y: bytes | None
    def rsa_oaep_encrypt(self, plaintext: bytes, hash_algorithm: str = "sha256") -> bytes: ...
    def rsa_pkcs1v15_encrypt(self, plaintext: bytes) -> bytes: ...
    def kem_encapsulate(self) -> tuple[bytes, bytes]: ...
    def verify_signature(
        self,
        signature: bytes,
        data: bytes,
        algorithm: str | None = None,
        context: bytes | None = None,
    ) -> None: ...

PrivateKey

Construction

PrivateKey.from_pem(data: bytes, password: bytes | None = None) -> PrivateKey

Load from PEM-encoded data (optionally password-protected).

PrivateKey.from_der(data: bytes) -> PrivateKey

Load from unencrypted PKCS#8 DER bytes.

PrivateKey.from_pkcs8_encrypted(data: bytes, password: bytes) -> PrivateKey

Decrypt and load from PKCS#8 EncryptedPrivateKeyInfo DER.

Serialisation

key.to_pem() -> bytes
key.to_der() -> bytes   # unencrypted PKCS#8 DER

Properties

PropertyTypeDescription
key_typestrSame values as PublicKey.key_type
key_sizeint | NoneKey size in bits, or None

Methods

key.public_key() -> PublicKey              # extract the matching public key
key.sign(data: bytes, algorithm: str | None = None, context: bytes | None = None) -> bytes
key.rsa_oaep_decrypt(ciphertext: bytes, hash_algorithm: str = "sha256") -> bytes
key.rsa_pkcs1v15_decrypt(ciphertext: bytes) -> bytes
key.kem_decapsulate(ciphertext: bytes) -> bytes   # ML-KEM: returns shared_secret

Full class stub

class PrivateKey:
    @staticmethod
    def from_pem(data: bytes, password: bytes | None = None) -> PrivateKey: ...
    @staticmethod
    def from_der(data: bytes) -> PrivateKey: ...
    @staticmethod
    def from_pkcs8_encrypted(data: bytes, password: bytes) -> PrivateKey: ...
    def to_pem(self) -> bytes: ...
    def to_der(self) -> bytes: ...
    key_type: str
    key_size: int | None
    def public_key(self) -> PublicKey: ...
    def sign(
        self,
        data: bytes,
        algorithm: str | None = None,
        context: bytes | None = None,
    ) -> bytes: ...
    def rsa_oaep_decrypt(self, ciphertext: bytes, hash_algorithm: str = "sha256") -> bytes: ...
    def rsa_pkcs1v15_decrypt(self, ciphertext: bytes) -> bytes: ...
    def kem_decapsulate(self, ciphertext: bytes) -> bytes: ...

Usage

import synta

# Load a certificate and verify a signature using the embedded public key
cert = synta.Certificate.from_der(open("cert.der", "rb").read())
pub_key = synta.PublicKey.from_der(cert.public_key)
# For ECDSA with SHA-256:
try:
    pub_key.verify_signature(signature, message, algorithm="sha256")
    print("Valid")
except ValueError:
    print("Invalid")

# Load a private key and sign
priv_key = synta.PrivateKey.from_pem(open("key.pem", "rb").read())
sig = priv_key.sign(message, algorithm="sha256")

# ML-KEM key exchange
kem_pub = synta.PublicKey.from_der(kem_pub_der)
ciphertext, shared_secret = kem_pub.kem_encapsulate()

priv_kem = synta.PrivateKey.from_der(kem_priv_der)
recovered = priv_kem.kem_decapsulate(ciphertext)
assert shared_secret == recovered

See also PKCS#8 for parsing PKCS#8 private-key envelopes and CMS-KEM for RFC 9629 quantum-safe KEM recipient structures.