Pure-Python RSA implementation for encryption, decryption, signing, and verification
—
PKCS#1 v1.5 encryption, decryption, signing, and signature verification operations with support for multiple hash algorithms and secure cryptographic practices.
Encrypt messages using RSA public key cryptography with PKCS#1 v1.5 padding.
def encrypt(message: bytes, pub_key: PublicKey) -> bytes:
"""
Encrypts the given message using PKCS#1 v1.5.
Parameters:
- message: bytes - the message to encrypt (max length: k-11 bytes where k is key size in bytes)
- pub_key: PublicKey - the public key to encrypt with
Returns:
bytes - encrypted message as bytes
Raises:
- OverflowError: when the message is too large for the key size
"""Usage Example:
import rsa
# Generate keys
(public_key, private_key) = rsa.newkeys(2048)
# Encrypt a message
message = b'Hello, World!'
encrypted = rsa.encrypt(message, public_key)
# Encrypted data is the same length as the key
print(f"Encrypted length: {len(encrypted)} bytes")Decrypt messages that were encrypted with the corresponding public key.
def decrypt(crypto: bytes, priv_key: PrivateKey) -> bytes:
"""
Decrypts the given message using PKCS#1 v1.5.
Parameters:
- crypto: bytes - encrypted message to decrypt
- priv_key: PrivateKey - the private key to decrypt with
Returns:
bytes - decrypted message as bytes
Raises:
- DecryptionError: when decryption fails (wrong key, corrupted data, etc.)
"""Usage Example:
import rsa
# Decrypt the message
try:
decrypted = rsa.decrypt(encrypted, private_key)
print(decrypted.decode('utf-8')) # Convert bytes to string
except rsa.DecryptionError:
print("Decryption failed - wrong key or corrupted data")Create digital signatures for messages using RSA private keys with various hash algorithms.
def sign(message: bytes, priv_key: PrivateKey, hash_method: str) -> bytes:
"""
Signs a message using the private key.
Parameters:
- message: bytes - the message to sign
- priv_key: PrivateKey - the private key to sign with
- hash_method: str - hash algorithm ('SHA-1', 'SHA-224', 'SHA-256', 'SHA-384', 'SHA-512', 'MD5')
Returns:
bytes - signature as bytes
Raises:
- ValueError: for unsupported hash methods
"""
def sign_hash(hash_value: bytes, priv_key: PrivateKey, hash_method: str) -> bytes:
"""
Signs a pre-computed hash value.
Parameters:
- hash_value: bytes - the hash to sign (must match hash_method)
- priv_key: PrivateKey - the private key to sign with
- hash_method: str - hash algorithm used to create hash_value
Returns:
bytes - signature as bytes
"""Usage Example:
import rsa
# Sign a message
message = b'Important document content'
signature = rsa.sign(message, private_key, 'SHA-256')
# Sign a pre-computed hash
import hashlib
hash_obj = hashlib.sha256(message)
hash_bytes = hash_obj.digest()
signature = rsa.sign_hash(hash_bytes, private_key, 'SHA-256')Verify digital signatures to ensure message authenticity and integrity.
def verify(message: bytes, signature: bytes, pub_key: PublicKey) -> str:
"""
Verifies a message signature.
Parameters:
- message: bytes - the original message
- signature: bytes - the signature to verify
- pub_key: PublicKey - the public key to verify with
Returns:
str - the hash method used for signing ('SHA-256', etc.)
Raises:
- VerificationError: when signature verification fails
"""
def find_signature_hash(signature: bytes, pub_key: PublicKey) -> str:
"""
Finds the hash method used in a signature.
Parameters:
- signature: bytes - the signature to analyze
- pub_key: PublicKey - the public key used for verification
Returns:
str - the hash method name ('SHA-256', etc.)
Raises:
- VerificationError: when signature cannot be processed
"""Usage Example:
import rsa
# Verify a signature
try:
hash_method = rsa.verify(message, signature, public_key)
print(f"Signature valid - signed with {hash_method}")
except rsa.VerificationError:
print("Signature verification failed")
# Determine hash method without full verification
try:
hash_method = rsa.find_signature_hash(signature, public_key)
print(f"Signature uses {hash_method}")
except rsa.VerificationError:
print("Cannot determine hash method")Compute cryptographic hashes for messages using supported algorithms.
def compute_hash(message: Union[bytes, BinaryIO], method_name: str) -> bytes:
"""
Computes a hash of the given message.
Parameters:
- message: bytes or file-like object - data to hash
- method_name: str - hash algorithm ('SHA-1', 'SHA-224', 'SHA-256', 'SHA-384', 'SHA-512', 'MD5')
Returns:
bytes - computed hash value
Raises:
- ValueError: for unsupported hash methods
"""Usage Example:
import rsa
# Hash a message
message = b'Data to hash'
hash_value = rsa.compute_hash(message, 'SHA-256')
# Hash a file
with open('document.txt', 'rb') as f:
hash_value = rsa.compute_hash(f, 'SHA-256')class CryptoError(Exception):
"""Base class for all cryptographic errors."""
class DecryptionError(CryptoError):
"""Raised when decryption fails due to wrong key, corrupted data, or padding errors."""
class VerificationError(CryptoError):
"""Raised when signature verification fails due to invalid signature or wrong key."""| Algorithm | Security | Recommended |
|---|---|---|
| SHA-256 | High | ✓ Recommended |
| SHA-384 | High | ✓ Recommended |
| SHA-512 | High | ✓ Recommended |
| SHA-224 | Medium | ✓ Acceptable |
| SHA-1 | Low | ⚠️ Deprecated |
| MD5 | Very Low | ❌ Not recommended |
RSA encryption has strict message size limitations based on key size and padding:
(key_size_in_bytes - 11) bytesFor larger messages, use hybrid encryption (encrypt a symmetric key with RSA, then encrypt the message with the symmetric key).
poolsize > 1 in newkeys() for faster key generationInstall with Tessl CLI
npx tessl i tessl/pypi-rsa