Skip to content

Commit 66c378a

Browse files
Merge pull request steam-bell-92#1566 from KunwarSidhu47/fix/syntax-error-and-ciphers
[Feature]: Upgrade Caesar Cipher project to include more ciphers (Vigenère, Playfair, RSA)
2 parents 186db9a + 854a86b commit 66c378a

5 files changed

Lines changed: 610 additions & 138 deletions

File tree

Lines changed: 243 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,282 @@
1+
import random
2+
13
def caesar_cipher(message: str, shift: int, mode: str) -> str:
2-
# If decrypting, we just reverse the shift direction
34
if mode.upper() in ["D", "DECRYPT"]:
45
shift = -shift
56

67
shift %= 26
78
result = ""
89

9-
# Core Caesar Cipher Logic
1010
for char in message:
1111
if char.isascii() and char.isalpha():
12-
# Determine ASCII boundary (uppercase vs lowercase)
1312
start = ord('A') if char.isupper() else ord('a')
14-
15-
# Shift character and wrap around using modulo 26
1613
shifted_pos = (ord(char) - start + shift) % 26
1714
new_char = chr(start + shifted_pos)
1815
result += new_char
1916
else:
20-
# Leave spaces, numbers, and punctuation untouched
2117
result += char
2218

2319
return result
2420

21+
def vigenere_cipher(message: str, keyword: str, mode: str) -> str:
22+
result = ""
23+
keyword = "".join([c.upper() for c in keyword if c.isalpha()])
24+
if not keyword:
25+
return message
26+
27+
keyword_idx = 0
28+
for char in message:
29+
if char.isascii() and char.isalpha():
30+
start = ord('A') if char.isupper() else ord('a')
31+
shift = ord(keyword[keyword_idx % len(keyword)]) - ord('A')
32+
33+
if mode.upper() in ["D", "DECRYPT"]:
34+
shift = -shift
35+
36+
shifted_pos = (ord(char) - start + shift) % 26
37+
result += chr(start + shifted_pos)
38+
keyword_idx += 1
39+
else:
40+
result += char
41+
return result
42+
43+
def atbash_cipher(message: str) -> str:
44+
result = ""
45+
for char in message:
46+
if char.isascii() and char.isalpha():
47+
if char.isupper():
48+
result += chr(ord('Z') - (ord(char) - ord('A')))
49+
else:
50+
result += chr(ord('z') - (ord(char) - ord('a')))
51+
else:
52+
result += char
53+
return result
54+
55+
def generate_playfair_matrix(keyword: str) -> list:
56+
keyword = "".join([c.upper() for c in keyword if c.isalpha()]).replace("J", "I")
57+
matrix = []
58+
seen = set()
59+
60+
for char in keyword + "ABCDEFGHIKLMNOPQRSTUVWXYZ":
61+
if char not in seen:
62+
seen.add(char)
63+
matrix.append(char)
64+
65+
return [matrix[i:i+5] for i in range(0, 25, 5)]
66+
67+
def find_position(matrix: list, char: str) -> tuple:
68+
for row in range(5):
69+
for col in range(5):
70+
if matrix[row][col] == char:
71+
return row, col
72+
return -1, -1
73+
74+
def playfair_cipher(message: str, keyword: str, mode: str) -> str:
75+
matrix = generate_playfair_matrix(keyword)
76+
77+
msg = "".join([c.upper() for c in message if c.isalpha()]).replace("J", "I")
78+
if not msg:
79+
return ""
80+
81+
processed_msg = ""
82+
i = 0
83+
while i < len(msg):
84+
processed_msg += msg[i]
85+
if i + 1 < len(msg):
86+
if msg[i] == msg[i+1] and mode.upper() in ["E", "ENCRYPT"]:
87+
processed_msg += "X"
88+
else:
89+
processed_msg += msg[i+1]
90+
i += 1
91+
else:
92+
if mode.upper() in ["E", "ENCRYPT"]:
93+
processed_msg += "X"
94+
i += 1
95+
96+
result = ""
97+
shift = 1 if mode.upper() in ["E", "ENCRYPT"] else -1
98+
99+
for i in range(0, len(processed_msg) - 1, 2):
100+
char1, char2 = processed_msg[i], processed_msg[i+1]
101+
r1, c1 = find_position(matrix, char1)
102+
r2, c2 = find_position(matrix, char2)
103+
104+
if r1 == r2:
105+
result += matrix[r1][(c1 + shift) % 5]
106+
result += matrix[r2][(c2 + shift) % 5]
107+
elif c1 == c2:
108+
result += matrix[(r1 + shift) % 5][c1]
109+
result += matrix[(r2 + shift) % 5][c2]
110+
else:
111+
result += matrix[r1][c2]
112+
result += matrix[r2][c1]
113+
114+
return result
115+
116+
# RSA implementation
117+
def is_prime(n):
118+
if n <= 1: return False
119+
if n <= 3: return True
120+
if n % 2 == 0 or n % 3 == 0: return False
121+
i = 5
122+
while i * i <= n:
123+
if n % i == 0 or n % (i + 2) == 0: return False
124+
i += 6
125+
return True
126+
127+
def generate_prime(min_val=10, max_val=100):
128+
prime = random.randint(min_val, max_val)
129+
while not is_prime(prime):
130+
prime = random.randint(min_val, max_val)
131+
return prime
132+
133+
def gcd(a, b):
134+
while b != 0:
135+
a, b = b, a % b
136+
return a
137+
138+
def mod_inverse(e, phi):
139+
for d in range(2, phi):
140+
if (d * e) % phi == 1:
141+
return d
142+
return None
143+
144+
def generate_rsa_keys():
145+
p = generate_prime(10, 100)
146+
q = generate_prime(10, 100)
147+
while p == q:
148+
q = generate_prime(10, 100)
149+
150+
n = p * q
151+
phi = (p - 1) * (q - 1)
152+
153+
e = random.randrange(2, phi)
154+
while gcd(e, phi) != 1:
155+
e = random.randrange(2, phi)
156+
157+
d = mod_inverse(e, phi)
158+
while d is None:
159+
e = random.randrange(2, phi)
160+
while gcd(e, phi) != 1:
161+
e = random.randrange(2, phi)
162+
d = mod_inverse(e, phi)
163+
164+
return ((e, n), (d, n))
165+
166+
def rsa_encrypt(message, public_key):
167+
e, n = public_key
168+
cipher = [(ord(char) ** e) % n for char in message]
169+
return cipher
170+
171+
def rsa_decrypt(cipher, private_key):
172+
d, n = private_key
173+
message = "".join([chr((char ** d) % n) for char in cipher])
174+
return message
25175

26176
def main() -> None:
27-
print("🔐 Caesar Cipher Encryptor & Decryptor 🔐")
177+
print("🔐 Cipher Suite (Caesar, Vigenère, Atbash, Playfair, RSA) 🔐")
28178
print("Hide your secret messages or reveal them! \n")
29179

30180
while True:
31-
choice = input(
32-
"🎯 Choose Operation: Encrypt (E), Decrypt (D), or Quit (Q): "
33-
).upper()
181+
print("\n--- Main Menu ---")
182+
print("1. Caesar Cipher")
183+
print("2. Vigenère Cipher")
184+
print("3. Atbash Cipher")
185+
print("4. Playfair Cipher")
186+
print("5. Basic RSA Algorithm")
187+
print("0. Quit")
188+
189+
choice = input("🎯 Choose an option (0-5): ").strip()
34190

35-
if choice in ["Q", "QUIT"]:
191+
if choice == "0":
36192
break
37193

38-
elif choice in ["E", "ENCRYPT", "D", "DECRYPT"]:
39-
message = input("📝 Enter your message: ")
40-
41-
if not message.strip():
42-
print("❌ Error: Message cannot be empty.\n")
194+
if choice not in ["1", "2", "3", "4", "5"]:
195+
print("⚠️ Invalid input. Please select a valid option.\n")
196+
continue
197+
198+
if choice == "5":
199+
print("\n--- Basic RSA Algorithm ---")
200+
rsa_op = input("🎯 Choose: Generate Keys (G), Encrypt (E), Decrypt (D): ").upper()
201+
if rsa_op in ["G", "GENERATE"]:
202+
pub, priv = generate_rsa_keys()
203+
print(f"\n✨ Keys Generated!")
204+
print(f"👉 Public Key (e, n): {pub}")
205+
print(f"👉 Private Key (d, n): {priv}")
206+
print("Keep your private key secret!")
43207
continue
208+
elif rsa_op in ["E", "ENCRYPT"]:
209+
message = input("📝 Enter your message: ")
210+
if not message:
211+
print("❌ Error: Message cannot be empty.\n")
212+
continue
213+
try:
214+
e = int(input("🔑 Enter Public Key 'e': "))
215+
n = int(input("🔑 Enter Public Key 'n': "))
216+
cipher = rsa_encrypt(message, (e, n))
217+
print(f"\n✨ Encrypted Message (array of numbers):")
218+
print(f"👉 {cipher}")
219+
except ValueError:
220+
print("❌ Error: Key components must be integers.")
221+
elif rsa_op in ["D", "DECRYPT"]:
222+
cipher_str = input("📝 Enter your encrypted message (comma separated numbers): ")
223+
try:
224+
cipher = [int(x.strip()) for x in cipher_str.split(',') if x.strip()]
225+
if not cipher:
226+
print("❌ Error: Message cannot be empty.\n")
227+
continue
228+
d = int(input("🔑 Enter Private Key 'd': "))
229+
n = int(input("🔑 Enter Private Key 'n': "))
230+
message = rsa_decrypt(cipher, (d, n))
231+
print(f"\n✨ Decrypted Message:")
232+
print(f"👉 {message}")
233+
except ValueError:
234+
print("❌ Error: Invalid input format. Numbers expected.")
235+
else:
236+
print("⚠️ Invalid operation for RSA.\n")
237+
continue
44238

45-
non_alpha = sum(1 for c in message if not (c.isascii() and c.isalpha()))
46-
if non_alpha > 0:
47-
print(f"⚠️ Warning: {non_alpha} non-alphabetic character(s) will be left unchanged.\n")
239+
op = input("🎯 Choose Operation: Encrypt (E) or Decrypt (D): ").upper()
240+
if op not in ["E", "ENCRYPT", "D", "DECRYPT"]:
241+
print("⚠️ Invalid operation.\n")
242+
continue
48243

244+
message = input("📝 Enter your message: ")
245+
if not message.strip():
246+
print("❌ Error: Message cannot be empty.\n")
247+
continue
248+
249+
result = ""
250+
251+
if choice == "1":
49252
try:
50253
shift = int(input("🔑 Enter the shift key (whole number): "))
254+
result = caesar_cipher(message, shift, op)
51255
except ValueError:
52256
print("❌ Error: Shift key must be a valid whole number.\n")
53257
continue
54-
55-
result = caesar_cipher(message, shift, choice)
56-
57-
print("\n✨ Resulting Message:")
58-
print(f"👉 {result}\n")
258+
259+
elif choice == "2":
260+
keyword = input("🔑 Enter the keyword: ")
261+
if not any(c.isalpha() for c in keyword):
262+
print("❌ Error: Keyword must contain letters.\n")
263+
continue
264+
result = vigenere_cipher(message, keyword, op)
59265

60-
else:
61-
print("⚠️ Invalid input. Please type E, D, or Q.\n")
266+
elif choice == "3":
267+
result = atbash_cipher(message)
62268

63-
print("\n👋 Thanks for using the Caesar Cipher! Stay secure! 🕵️‍♂️\n")
64-
269+
elif choice == "4":
270+
keyword = input("🔑 Enter the keyword: ")
271+
if not any(c.isalpha() for c in keyword):
272+
print("❌ Error: Keyword must contain letters.\n")
273+
continue
274+
result = playfair_cipher(message, keyword, op)
275+
276+
print("\n✨ Resulting Message:")
277+
print(f"👉 {result}\n")
278+
279+
print("\n👋 Thanks for using the Cipher Suite! Stay secure! 🕵️‍♂️\n")
65280

66281
if __name__ == "__main__":
67282
main()

web-app/js/main.js

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,49 +1550,36 @@ card.appendChild(badge);
15501550
e.stopPropagation();
15511551
var favs = JSON.parse(localStorage.getItem("favorites") || "[]");
15521552
var idx = favs.indexOf(name);
1553+
15531554
if (idx === -1) {
1555+
// Add to favorites
15541556
favs.push(name);
15551557
favBtn.classList.add("active");
15561558
favBtn.innerHTML = '<i class="fas fa-star"></i>';
1559+
favBtn.style.color = "#f5a623"; // Yellow
1560+
console.log("⭐ Added " + name + " to favorites");
15571561
} else {
1562+
// Remove from favorites
15581563
favs.splice(idx, 1);
15591564
favBtn.classList.remove("active");
15601565
favBtn.innerHTML = '<i class="far fa-star"></i>';
1566+
favBtn.style.color = ""; // Reset to default
1567+
console.log("☆ Removed " + name + " from favorites");
15611568
if (currentCategory === "favorites") {
15621569
card.style.display = "none";
15631570
}
15641571
}
1572+
15651573
localStorage.setItem("favorites", JSON.stringify(favs));
1566-
updateSidebarCategoryCounts();
1574+
1575+
// Update badge and counts
1576+
if (typeof updateSidebarCategoryCounts === 'function') {
1577+
updateSidebarCategoryCounts();
1578+
}
1579+
if (typeof updateFavoritesCountBadge === 'function') {
1580+
updateFavoritesCountBadge();
1581+
}
15671582
});
1568-
e.stopPropagation();
1569-
var favs = JSON.parse(localStorage.getItem("favorites") || "[]");
1570-
var idx = favs.indexOf(name);
1571-
1572-
if (idx === -1) {
1573-
// Add to favorites
1574-
favs.push(name);
1575-
favBtn.classList.add("active");
1576-
favBtn.innerHTML = '<i class="fas fa-star"></i>';
1577-
favBtn.style.color = "#f5a623"; // Yellow
1578-
console.log("⭐ Added " + name + " to favorites");
1579-
} else {
1580-
// Remove from favorites
1581-
favs.splice(idx, 1);
1582-
favBtn.classList.remove("active");
1583-
favBtn.innerHTML = '<i class="far fa-star"></i>';
1584-
favBtn.style.color = ""; // Reset to default
1585-
console.log("☆ Removed " + name + " from favorites");
1586-
if (currentCategory === "favorites") {
1587-
card.style.display = "none";
1588-
}
1589-
}
1590-
1591-
localStorage.setItem("favorites", JSON.stringify(favs));
1592-
1593-
// Update badge
1594-
updateFavoritesCountBadge();
1595-
});
15961583

15971584
var cardActions = card.querySelector(".card-actions");
15981585
if (cardActions) cardActions.appendChild(favBtn);

0 commit comments

Comments
 (0)