How Symmetric and Asymmetric Encryption Algorithms Work in TheAlgorithms/Python

Symmetric algorithms use a single shared key for encryption and decryption, while asymmetric RSA uses mathematically linked public and private keys for secure communication without shared secrets.

TheAlgorithms/Python repository provides educational implementations of both symmetric and asymmetric encryption algorithms, offering clean, self-contained Python code that demonstrates fundamental cryptographic concepts. The ciphers package contains classic symmetric ciphers like Caesar and Vigenère alongside a complete RSA implementation, making it an ideal reference for understanding how encryption functions at the code level.

Symmetric Encryption Algorithms

Symmetric ciphers in the repository use the same secret key for both encryption and decryption operations. These implementations operate directly on strings and bytes, making them lightweight and easy to understand.

Caesar Cipher

The Caesar cipher implementation in ciphers/caesar_cipher.py performs a simple character shift using modular arithmetic.

  • Encryption: Shifts each character's ASCII code by a constant offset
  • Decryption: Shifts in the reverse direction by the same offset
  • Key: Integer shift value (typically 0-255)
from ciphers.caesar_cipher import encrypt, decrypt

ciphertext = encrypt("Hello World!", shift=3)  # → "Khoor Zruog!"

plaintext = decrypt(ciphertext, shift=3)       # → "Hello World!"

Vigenère Cipher

Located in ciphers/vigenere_cipher.py, this implementation extends the Caesar concept by using a repeating keyword to drive variable shifts.

  • Core mechanism: Each character in the keyword determines the shift amount for the corresponding plaintext character
  • Key: Text string (ASCII letters) that repeats to match message length
  • Security: Stronger than Caesar but still vulnerable to frequency analysis
from ciphers.vigenere_cipher import encrypt, decrypt

key = "SECRET"
encrypted = encrypt("Attack at dawn", key)
decrypted = decrypt(encrypted, key)

XOR Cipher

The ciphers/xor_cipher.py module implements bitwise XOR encryption, where the same operation serves as both encryption and decryption.

  • Mechanism: Each byte is XORed with a corresponding byte from the repeating key
  • Key property: plaintext XOR key = ciphertext, and ciphertext XOR key = plaintext
  • Implementation: Single encrypt() function handles both directions
from ciphers.xor_cipher import encrypt

message = "Hello"
key = "K"
encrypted = encrypt(message, key)  # Encrypt

decrypted = encrypt(encrypted, key)  # Decrypt (same function)

One-Time Pad (OTP)

Found in ciphers/onepad_cipher.py, this implementation provides theoretically unbreakable encryption when used correctly.

  • Requirement: Key must be truly random, as long as the message, and used only once
  • Mechanism: Byte-wise XOR between message and key
  • Security: Information-theoretically secure, unlike computationally secure algorithms
from ciphers.onepad_cipher import encrypt
import os

message = "Secret message"
key = os.urandom(len(message))  # Truly random key

ciphertext = encrypt(message, key)

Hill Cipher

The ciphers/hill_cipher.py implementation uses linear algebra for encryption, treating blocks of text as vectors and applying matrix transformations.

  • Mechanism: Multiplies plaintext vector by key matrix modulo 26
  • Key: Square invertible matrix (size 2×2 or 3×3) with determinant coprime to 26
  • Decryption: Uses modular inverse of the key matrix
from ciphers.hill_cipher import encrypt, decrypt
import numpy as np

key_matrix = [[3, 3], [2, 5]]  # Must be invertible mod 26

encrypted = encrypt("HELP", key_matrix)

Asymmetric RSA Implementation

The RSA implementation in TheAlgorithms/Python provides a complete public-key cryptosystem split across two modules: rsa_key_generator.py for key creation and rsa_cipher.py for encryption operations.

Key Generation (rsa_key_generator.py)

The generate_key() function in ciphers/rsa_key_generator.py creates mathematically linked public and private key pairs using large prime numbers.

Key generation process:

  1. Prime generation: Uses the Miller-Rabin probabilistic test (rabin_miller.generate_large_prime) to generate two distinct large primes p and q
  2. Modulus calculation: Computes n = p * q (the RSA modulus)
  3. Totient calculation: Calculates φ(n) = (p-1) × (q-1)
  4. Public exponent selection: Chooses random e such that gcd(e, φ(n)) == 1
  5. Private exponent calculation: Computes modular inverse d = find_mod_inverse(e, φ(n))
  6. File storage: Writes keys to <name>_pubkey.txt and <name>_privkey.txt in CSV format (key_size,n,eor_d)
from ciphers.rsa_key_generator import make_key_files

# Generate 1024-bit RSA keys and save to disk

make_key_files("myrsa", 1024)  # Creates myrsa_pubkey.txt & myrsa_privkey.txt

Encryption and Decryption (rsa_cipher.py)

The ciphers/rsa_cipher.py module handles the actual cryptographic operations using modular exponentiation.

Block handling mechanism:

  • Text is broken into blocks of block_size bytes (default 128)
  • Each block is interpreted as a base-256 integer (BYTE_SIZE = 256)
  • Encryption: cipher_block = pow(plain_block, e, n)
  • Decryption: plain_block = pow(cipher_block, d, n)

Core functions:

  • encrypt_message(message: str, key: Tuple[int, int]) → List[int]: Encrypts string to list of integer blocks
  • decrypt_message(blocks: List[int], message_length: int, key: Tuple[int, int]) → str: Decrypts blocks back to original string
  • encrypt_and_write_to_file(...): Convenience function for file-based encryption
  • read_from_file_and_decrypt(...): File-based decryption helper

Practical Usage Example

This complete example demonstrates the full RSA lifecycle from key generation to message recovery:

from ciphers.rsa_key_generator import make_key_files
from ciphers.rsa_cipher import encrypt_and_write_to_file, read_from_file_and_decrypt

# 1️⃣ Generate a fresh 1024-bit RSA key pair (only needs to be done once)

make_key_files("myrsa", 1024)          # creates myrsa_pubkey.txt & myrsa_privkey.txt

# 2️⃣ Encrypt a message using the public key

plaintext = "Confidential data inside RSA"
encrypt_and_write_to_file(
    message_filename="secret.txt",
    key_filename="myrsa_pubkey.txt",
    message=plaintext,
    block_size=128
)

# 3️⃣ Decrypt using the private key

decrypted = read_from_file_and_decrypt("secret.txt", "myrsa_privkey.txt")
print("Recovered text:", decrypted)    # → "Confidential data inside RSA"

Summary

  • Symmetric ciphers in TheAlgorithms/Python use a single shared secret key for both encryption and decryption, implementing classic algorithms like Caesar, Vigenère, XOR, One-Time Pad, and Hill cipher in pure Python.
  • Asymmetric RSA provides a complete public-key cryptosystem across rsa_key_generator.py and rsa_cipher.py, generating mathematically linked key pairs using prime numbers and modular arithmetic for secure communication without shared secrets.
  • All implementations are self-contained, require no external cryptography libraries, and serve as educational references for understanding encryption fundamentals at the source code level.

Frequently Asked Questions

What is the difference between symmetric and asymmetric encryption in the repository?

Symmetric encryption algorithms like Caesar and Vigenère use the same key for both encryption and decryption, making them fast but requiring secure key distribution. Asymmetric RSA uses mathematically linked public and private keys, allowing anyone to encrypt with the public key while only the private key holder can decrypt, solving the key distribution problem at the cost of computational overhead.

How does the RSA key generation process work in TheAlgorithms/Python?

The generate_key() function in ciphers/rsa_key_generator.py uses the Miller-Rabin primality test to generate two large random primes p and q, computes the modulus n = p × q, calculates Euler's totient φ(n) = (p-1)(q-1), selects a public exponent e coprime to φ(n), and computes the private exponent d as the modular multiplicative inverse of e modulo φ(n).

Can the symmetric ciphers in this repository be used for production security?

No, the symmetric implementations in ciphers/caesar_cipher.py, ciphers/vigenere_cipher.py, and similar files are designed for educational purposes to illustrate classical cryptography concepts. While the One-Time Pad (ciphers/onepad_cipher.py) is theoretically unbreakable when used with truly random keys of equal length to the message, the other classical ciphers are vulnerable to modern cryptanalysis and should not be used for securing sensitive data in production environments.

How does block handling work in the RSA implementation?

The RSA cipher in ciphers/rsa_cipher.py processes text in fixed-size blocks (default 128 bytes) to accommodate the mathematical constraints of modular arithmetic. Each block is converted to a large integer by treating the bytes as a base-256 number, then encrypted using modular exponentiation (pow(block, e, n)). During decryption, the process reverses using the private exponent d, and the resulting integers are converted back to bytes, with the original message length preserved to handle padding correctly.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →