Of course! Here is a comprehensive guide to using RSA with Python on Windows. We'll cover the standard library approach, the more user-friendly cryptography library, and how to handle keys in files, which is a common requirement.

Summary of Approaches
| Library | Pros | Cons | Best For |
|---|---|---|---|
rsa (PyPI) |
Very simple API, great for beginners. | Slower than cryptography, less actively maintained for new features. |
Quick scripts, learning the basics, simple encryption/decryption tasks. |
cryptography (PyPI) |
Industry standard, high performance, actively maintained, secure. | API is more complex and object-oriented. | Production applications, high-performance needs, and serious security work. |
Option 1: The Simple rsa Library (Recommended for Beginners)
This is the easiest way to get started. You just need to install it.
Step 1: Installation
Open Command Prompt or PowerShell and run:
pip install rsa
Step 2: Generate RSA Keys
The first step is to create a public/private key pair. The private key contains both the public and private parts, while the public key only contains the public part. You must keep the private key secret!
import rsa
# Generate a new 2048-bit key pair
# 2048 bits is a common and secure key size.
(public_key, private_key) = rsa.newkeys(2048)
print("Public Key:")
print(public_key.save_pkcs1().decode('utf-8'))
print("\nPrivate Key:")
print(private_key.save_pkcs1().decode('utf-8'))
Output:

Public Key:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAx... (long string of characters) ...QIDAQAB
-----END RSA PUBLIC KEY-----
Private Key:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAx... (long string of characters) ...wIDAQAB
-----END RSA PRIVATE KEY-----
The save_pkcs1() method saves the key in a standard format (PKCS#1). The .decode('utf-8') converts the bytes to a string so you can print or save it to a file.
Step 3: Encrypt and Decrypt
Now you can use the public key to encrypt a message and the private key to decrypt it.
Important: RSA can only encrypt a small amount of data (depending on the key size). For 2048-bit keys, the maximum is 245 bytes. For longer messages, you must use a hybrid approach (encrypt a symmetric key with RSA, then encrypt the data with that key), which we'll show with the cryptography library.
import rsa
# --- Keys from the previous step ---
public_key, private_key = rsa.newkeys(2048)
# --- Encryption ---
message = b"Hello, this is a secret message!" # Must be bytes
# Encrypt the message with the public key
encrypted_message = rsa.encrypt(message, public_key)
print(f"Original message: {message}")
print(f"Encrypted message (hex): {encrypted_message.hex()}")
# --- Decryption ---
# Decrypt the message with the private key
decrypted_message = rsa.decrypt(encrypted_message, private_key)
print(f"Decrypted message: {decrypted_message.decode('utf-8')}")
Step 4: Saving and Loading Keys from Files
It's impractical to generate keys every time. You should save them to files.

Save Keys:
import rsa
public_key, private_key = rsa.newkeys(2048)
# Save public key to a file
with open('public_key.pem', 'wb') as f:
f.write(public_key.save_pkcs1())
# Save private key to a file
with open('private_key.pem', 'wb') as f:
f.write(private_key.save_pkcs1())
print("Keys saved to 'public_key.pem' and 'private_key.pem'")
Load Keys:
import rsa
# Load public key from file
with open('public_key.pem', 'rb') as f:
public_key = rsa.PublicKey.load_pkcs1(f.read())
# Load private key from file
with open('private_key.pem', 'rb') as f:
private_key = rsa.PrivateKey.load_pkcs1(f.read())
print("Keys loaded successfully.")
# Now you can use them for encryption/decryption as before
message = b"Data loaded from files!"
encrypted = rsa.encrypt(message, public_key)
decrypted = rsa.decrypt(encrypted, private_key)
print(f"Decrypted: {decrypted.decode('utf-8')}")
Option 2: The Professional cryptography Library
This library is more robust and is the recommended choice for any serious application. It handles many edge cases and is optimized for performance.
Step 1: Installation
pip install cryptography
Step 2: Generate RSA Keys
The cryptography library uses an object-oriented approach.
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
# 1. Generate a private key
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
# 2. Get the public key from the private key
public_key = private_key.public_key()
# --- Save Keys to Files (PEM format) ---
# Save the private key
with open("private_key_cryptography.pem", "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption() # Or use BestAvailableEncryption(password)
))
# Save the public key
with open("public_key_cryptography.pem", "wb") as f:
f.write(public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
))
print("Keys saved using the cryptography library.")
Step 3: Encrypt and Decrypt (with OAEP Padding)
The cryptography library uses a more secure padding scheme by default (OAEP). We also need to handle the fact that RSA has a limited message size.
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
import os
# --- Load Keys from Files ---
with open("private_key_cryptography.pem", "rb") as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=None, # Set to b'your_password' if you encrypted the key
backend=default_backend()
)
with open("public_key_cryptography.pem", "rb") as f:
public_key = serialization.load_pem_public_key(
f.read(),
backend=default_backend()
)
# --- Encrypting a short message ---
message = b"Hello, cryptography!"
# Encrypt with the public key
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"Original message: {message}")
print(f"Ciphertext (hex): {ciphertext.hex()}")
# --- Decrypt with the private key ---
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"Decrypted message: {plaintext.decode('utf-8')}")
Step 4: Encrypting Large Files (Hybrid Encryption)
As mentioned, RSA can't encrypt large files directly. The standard solution is:
- Generate a strong, one-time symmetric key (like AES).
- Encrypt the large file using this symmetric key.
- Encrypt the symmetric key using the recipient's public RSA key.
- Send the encrypted file and the encrypted symmetric key to the recipient.
Here's a conceptual example:
# This is a simplified example. In practice, use libraries like 'cryptography.fernet'
# for symmetric encryption to handle padding, IVs, and modes correctly.
# --- Sender's Side ---
import os
# 1. Generate a random symmetric key (e.g., 32 bytes for AES-256)
symmetric_key = os.urandom(32)
large_file_data = b"This is the content of a very large file that cannot be encrypted directly with RSA." * 1000
# 2. Encrypt the file with the symmetric key (conceptual)
# In a real app, you would use Fernet or a Cipher object.
encrypted_file_data = b"ENCRYPTED_FILE_CONTENT_WITH_AES_" + large_file_data
# 3. Encrypt the symmetric key with the recipient's public key
encrypted_symmetric_key = public_key.encrypt(
symmetric_key,
padding.OAEP(...)
)
# Now, you would send `encrypted_file_data` and `encrypted_symmetric_key` to the recipient.
# --- Recipient's Side ---
# 1. Decrypt the symmetric key with your private key
decrypted_symmetric_key = private_key.decrypt(
encrypted_symmetric_key,
padding.OAEP(...)
)
# 2. Decrypt the file data with the decrypted symmetric key
# (conceptual)
decrypted_file_data = encrypted_file_data.replace(b"ENCRYPTED_FILE_CONTENT_WITH_AES_", b"")
print(f"Successfully decrypted a large piece of data: {decrypted_file_data[:50]}...")
Which One Should I Use?
- For a quick script, a school project, or just to learn the basics: Use the
rsalibrary. It's straightforward and gets the job done for small data. - For any application that will be used by others, for work, or for anything security-critical: Use the
cryptographylibrary. It's the industry standard, more secure, and much more performant. It's the right tool for the job.
