Skip to content

Rsa

provide.foundation.crypto.rsa

RSA digital signature implementation.

RSA-PSS signatures with SHA-256 for compatibility with existing systems. For new applications, prefer Ed25519 (faster, smaller keys, simpler).

Examples:

>>> signer = RSASigner.generate(key_size=2048)
>>> signature = signer.sign(b"message")
>>> verifier = RSAVerifier(signer.public_key_pem)
>>> assert verifier.verify(b"message", signature)

Classes

RSASigner

RSA digital signature signer.

Stateful signer for RSA-PSS signatures. Use Ed25519Signer for new applications; RSA is provided for compatibility with existing systems.

Examples:

Generate new keypair: >>> signer = RSASigner.generate(key_size=2048) >>> signature = signer.sign(b"message") >>> public_pem = signer.public_key_pem

Load existing key: >>> signer = RSASigner(private_key_pem=existing_pem) >>> signature = signer.sign(b"message")

Attributes
public_key_pem cached property
public_key_pem: str

Get RSA public key in PEM format.

Returns:

Name Type Description
str str

PEM-encoded public key

Functions
__attrs_post_init__
__attrs_post_init__() -> None

Initialize private key object from PEM.

Source code in provide/foundation/crypto/rsa.py
def __attrs_post_init__(self) -> None:
    """Initialize private key object from PEM."""
    _require_crypto()

    if self.private_key_pem is None:
        raise CryptoKeyError(
            "private_key_pem is required. Use RSASigner.generate() to create new keypair.",
            code="CRYPTO_MISSING_PRIVATE_KEY",
        )

    # Load private key from PEM
    object.__setattr__(
        self,
        "_private_key_obj",
        serialization.load_pem_private_key(
            self.private_key_pem.encode("utf-8"),
            password=None,
        ),
    )

    # Validate it's RSA
    if not isinstance(self._private_key_obj, rsa.RSAPrivateKey):
        raise CryptoKeyError(
            "Private key must be RSA",
            code="CRYPTO_INVALID_KEY_TYPE",
        )
export_private_key_pem
export_private_key_pem() -> str

Export private key in PEM format.

Returns:

Name Type Description
str str

PEM-encoded private key

Warning

Private keys should be stored securely. Consider encryption.

Source code in provide/foundation/crypto/rsa.py
def export_private_key_pem(self) -> str:
    """Export private key in PEM format.

    Returns:
        str: PEM-encoded private key

    Warning:
        Private keys should be stored securely. Consider encryption.
    """
    return self.private_key_pem  # type: ignore
generate classmethod
generate(key_size: int = DEFAULT_RSA_KEY_SIZE) -> Self

Generate new signer with random RSA keypair.

Parameters:

Name Type Description Default
key_size int

RSA key size in bits (2048, 3072, or 4096)

DEFAULT_RSA_KEY_SIZE

Returns:

Name Type Description
RSASigner Self

Signer with newly generated keypair

Source code in provide/foundation/crypto/rsa.py
@classmethod
def generate(cls, key_size: int = DEFAULT_RSA_KEY_SIZE) -> Self:
    """Generate new signer with random RSA keypair.

    Args:
        key_size: RSA key size in bits (2048, 3072, or 4096)

    Returns:
        RSASigner: Signer with newly generated keypair
    """
    _require_crypto()
    logger.debug(f"🔐 Generating new RSA signer ({key_size} bits)")

    private_key_obj = rsa.generate_private_key(
        public_exponent=65537,
        key_size=key_size,
    )

    private_key_pem = private_key_obj.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    ).decode("utf-8")

    return cls(private_key_pem=private_key_pem, key_size=key_size)
sign
sign(data: bytes) -> bytes

Sign data with RSA-PSS.

Uses PSS padding with SHA-256 hash, which is the modern recommended RSA signature scheme.

Parameters:

Name Type Description Default
data bytes

Data to sign

required

Returns:

Name Type Description
bytes bytes

RSA-PSS signature

Raises:

Type Description
CryptoSignatureError

If signature generation fails

Source code in provide/foundation/crypto/rsa.py
def sign(self, data: bytes) -> bytes:
    """Sign data with RSA-PSS.

    Uses PSS padding with SHA-256 hash, which is the modern recommended
    RSA signature scheme.

    Args:
        data: Data to sign

    Returns:
        bytes: RSA-PSS signature

    Raises:
        CryptoSignatureError: If signature generation fails
    """
    logger.debug(f"🔏 Signing {len(data)} bytes with RSA-PSS")

    try:
        signature = self._private_key_obj.sign(
            data,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH,
            ),
            hashes.SHA256(),
        )

        return signature
    except Exception as e:
        raise CryptoSignatureError(
            f"RSA signature generation failed: {e}",
            code="CRYPTO_SIGNATURE_FAILED",
        ) from e

RSAVerifier

RSA signature verifier.

Stateful verifier for RSA-PSS signatures.

Examples:

>>> signer = RSASigner.generate(key_size=2048)
>>> verifier = RSAVerifier(signer.public_key_pem)
>>> signature = signer.sign(b"message")
>>> assert verifier.verify(b"message", signature)
Functions
__attrs_post_init__
__attrs_post_init__() -> None

Initialize public key object from PEM.

Source code in provide/foundation/crypto/rsa.py
def __attrs_post_init__(self) -> None:
    """Initialize public key object from PEM."""
    _require_crypto()

    # Load public key from PEM
    object.__setattr__(
        self,
        "_public_key_obj",
        serialization.load_pem_public_key(self.public_key_pem.encode("utf-8")),
    )

    # Validate it's RSA
    if not isinstance(self._public_key_obj, rsa.RSAPublicKey):
        raise CryptoKeyError(
            "Public key must be RSA",
            code="CRYPTO_INVALID_KEY_TYPE",
        )
verify
verify(data: bytes, signature: bytes) -> bool

Verify RSA-PSS signature.

Parameters:

Name Type Description Default
data bytes

Data that was signed

required
signature bytes

RSA-PSS signature

required

Returns:

Name Type Description
bool bool

True if signature is valid, False otherwise

Source code in provide/foundation/crypto/rsa.py
def verify(self, data: bytes, signature: bytes) -> bool:
    """Verify RSA-PSS signature.

    Args:
        data: Data that was signed
        signature: RSA-PSS signature

    Returns:
        bool: True if signature is valid, False otherwise
    """
    logger.debug(f"🔍 Verifying RSA-PSS signature for {len(data)} bytes")

    try:
        self._public_key_obj.verify(
            signature,
            data,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH,
            ),
            hashes.SHA256(),
        )
        return True
    except Exception as e:
        logger.debug(f"❌ Invalid RSA-PSS signature: {e}")
        return False