Category: Cryptography
Topics: substitution cipher, Caesar cipher, encoding, obfuscation
A simple letter substitution cipher that replaces each letter with the letter 13 positions after it in the alphabet. Since the alphabet has 26 letters, applying ROT13 twice returns the original text.
tr command demonstrationsdef rot13(text):
"""
Apply ROT13 cipher to text.
Letters are rotated 13 positions, other characters unchanged.
"""
result = []
for char in text:
if 'a' <= char <= 'z':
# Lowercase: rotate within a-z
rotated = chr((ord(char) - ord('a') + 13) % 26 + ord('a'))
result.append(rotated)
elif 'A' <= char <= 'Z':
# Uppercase: rotate within A-Z
rotated = chr((ord(char) - ord('A') + 13) % 26 + ord('A'))
result.append(rotated)
else:
# Non-letters unchanged
result.append(char)
return ''.join(result)
def rot13_using_translate(text):
"""ROT13 using str.translate() - more Pythonic."""
import string
rot13_table = str.maketrans(
string.ascii_lowercase + string.ascii_uppercase,
string.ascii_lowercase[13:] + string.ascii_lowercase[:13] +
string.ascii_uppercase[13:] + string.ascii_uppercase[:13]
)
return text.translate(rot13_table)
def rot_n(text, n):
"""Generalized rotation cipher (Caesar cipher)."""
result = []
n = n % 26 # Normalize rotation
for char in text:
if 'a' <= char <= 'z':
rotated = chr((ord(char) - ord('a') + n) % 26 + ord('a'))
result.append(rotated)
elif 'A' <= char <= 'Z':
rotated = chr((ord(char) - ord('A') + n) % 26 + ord('A'))
result.append(rotated)
else:
result.append(char)
return ''.join(result)
def crack_caesar(ciphertext):
"""Try all 26 rotations to crack a Caesar cipher."""
results = []
for n in range(26):
decrypted = rot_n(ciphertext, n)
results.append((n, decrypted))
return results
# Usage examples
text = "Hello, World!"
encoded = rot13(text)
print(f"Original: {text}")
print(f"ROT13: {encoded}")
# ROT13 is self-inverse
decoded = rot13(encoded)
print(f"Decoded: {decoded}")
# Verify self-inverse property
assert rot13(rot13(text)) == text
# Using translate method
encoded2 = rot13_using_translate(text)
print(f"
Using translate: {encoded2}")
# Caesar cipher with different rotations
print(f"
ROT1: {rot_n(text, 1)}")
print(f"ROT5: {rot_n(text, 5)}")
print(f"ROT13: {rot_n(text, 13)}")
# Crack example
secret = rot_n("attack at dawn", 7)
print(f"
Cracking '{secret}':")
for n, attempt in crack_caesar(secret)[:5]:
print(f" ROT{n}: {attempt}")
| Operation | Complexity |
|---|---|
| Encode/Decode | O(n) |
| Crack Caesar | O(26n) = O(n) |
Where n = length of text. Single pass through the string.
O(n) for the output string. Can be O(1) if modifying in place (in languages that allow it).