-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcipher.py
More file actions
33 lines (22 loc) · 1.15 KB
/
Copy pathcipher.py
File metadata and controls
33 lines (22 loc) · 1.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import string
ALPHABET = "abcdefghijklmnopqrstuvwxyzæøå{}_"
def xor_char(a: str, b: str, alphabet: str = ALPHABET) -> str:
"""XOR one character from text with one key character."""
if a in string.whitespace:
return a
return alphabet[alphabet.index(a) ^ alphabet.index(b)]
def transform(text: str, key: str, alphabet: str = ALPHABET) -> str:
"""Encrypt/decrypt text using a single-character XOR key."""
if len(key) != 1:
raise ValueError("Key must be exactly one character")
if key not in alphabet:
raise ValueError("Key must exist in alphabet")
return "".join(xor_char(ch, key, alphabet) for ch in text)
def encrypt(text: str, key: str, alphabet: str = ALPHABET) -> str:
return transform(text, key, alphabet)
def decrypt(text: str, key: str, alphabet: str = ALPHABET) -> str:
# XOR is symmetric, so decrypt is identical to encrypt.
return transform(text, key, alphabet)
def brute_force_decrypt(ciphertext: str, alphabet: str = ALPHABET) -> dict[str, str]:
"""Return every possible plaintext candidate by trying all keys."""
return {key: decrypt(ciphertext, key, alphabet) for key in alphabet}