|
2 | 2 |
|
3 | 3 | class RC4: |
4 | 4 | def __init__(self, key: bytes): |
5 | | - self.key=key |
6 | | - self.s=self._ksa(key) |
| 5 | + self.key = key |
| 6 | + self.s = self._ksa(key) |
7 | 7 |
|
8 | 8 | def _ksa(self, key: bytes) -> List[int]: |
9 | | - """Key Scheduling Algorithm (KSA)""" |
10 | | - key_length=len(key) |
11 | | - s=list(range(256)) |
12 | | - j=0 |
| 9 | + """ |
| 10 | + Key Scheduling Algorithm (KSA) |
| 11 | + |
| 12 | + >>> rc4 = RC4(b"SecretKey") |
| 13 | + >>> len(rc4._ksa(b"SecretKey")) |
| 14 | + 256 |
| 15 | + """ |
| 16 | + key_length = len(key) |
| 17 | + s = list(range(256)) |
| 18 | + j = 0 |
13 | 19 | for i in range(256): |
14 | | - j=(j+s[i]+key[i%key_length])%256 |
15 | | - s[i],s[j]=s[j],s[i] |
| 20 | + j = (j + s[i] + key[i % key_length]) % 256 |
| 21 | + s[i], s[j] = s[j], s[i] |
16 | 22 | return s |
17 | 23 |
|
18 | 24 | def _prga(self) -> int: |
19 | | - """Pseudo-Random Generation Algorithm (PRGA)""" |
20 | | - i=0 |
21 | | - j=0 |
| 25 | + """ |
| 26 | + Pseudo-Random Generation Algorithm (PRGA) |
| 27 | + |
| 28 | + >>> rc4 = RC4(b"SecretKey") |
| 29 | + >>> prga = rc4._prga() |
| 30 | + >>> isinstance(next(prga), int) |
| 31 | + True |
| 32 | + """ |
| 33 | + i = 0 |
| 34 | + j = 0 |
22 | 35 | while True: |
23 | | - i=(i+1)%256 |
24 | | - j=(j+self.s[i])%256 |
25 | | - self.s[i],self.s[j]=self.s[j],self.s[i] |
26 | | - yield self.s[(self.s[i]+self.s[j])%256] |
| 36 | + i = (i + 1) % 256 |
| 37 | + j = (j + self.s[i]) % 256 |
| 38 | + self.s[i], self.s[j] = self.s[j], self.s[i] |
| 39 | + yield self.s[(self.s[i] + self.s[j]) % 256] |
27 | 40 |
|
28 | 41 | def _reset_state(self): |
29 | 42 | """Reset state for each encryption/decryption.""" |
30 | | - self.s=self._ksa(self.key) |
| 43 | + self.s = self._ksa(self.key) |
31 | 44 |
|
32 | | - def encrypt(self,plaintext:bytes)->bytes: |
33 | | - """Encrypt plaintext using RC4""" |
34 | | - self._reset_state() |
35 | | - prga=self._prga() |
36 | | - return bytes([p^next(prga) for p in plaintext]) |
| 45 | + def encrypt(self, plaintext: bytes) -> bytes: |
| 46 | + """ |
| 47 | + Encrypt plaintext using RC4 |
| 48 | + |
| 49 | + >>> rc4 = RC4(b"SecretKey") |
| 50 | + >>> plaintext = b"Hello" |
| 51 | + >>> encrypted = rc4.encrypt(plaintext) |
| 52 | + >>> len(encrypted) == len(plaintext) |
| 53 | + True |
| 54 | + """ |
| 55 | + self._reset_state() |
| 56 | + prga = self._prga() |
| 57 | + return bytes([p ^ next(prga) for p in plaintext]) |
37 | 58 |
|
38 | | - def decrypt(self,ciphertext:bytes)->bytes: |
39 | | - """Decrypt ciphertext using RC4 (Same as encryption)""" |
40 | | - return self.encrypt(ciphertext) |
| 59 | + def decrypt(self, ciphertext: bytes) -> bytes: |
| 60 | + """ |
| 61 | + Decrypt ciphertext using RC4 |
| 62 | + |
| 63 | + >>> rc4 = RC4(b"SecretKey") |
| 64 | + >>> ciphertext = rc4.encrypt(b"Hello") |
| 65 | + >>> rc4.decrypt(ciphertext) == b"Hello" |
| 66 | + True |
| 67 | + """ |
| 68 | + return self.encrypt(ciphertext) |
41 | 69 |
|
42 | 70 |
|
43 | 71 | if __name__ == "__main__": |
44 | | - key=b"SecretKey" |
45 | | - rc4=RC4(key) |
| 72 | + import doctest |
| 73 | + doctest.testmod() |
| 74 | + |
| 75 | + key = b"SecretKey" |
| 76 | + rc4 = RC4(key) |
46 | 77 |
|
47 | | - plaintext=b"Hello, RC4 Cipher!" |
48 | | - print("Original:",plaintext) |
| 78 | + plaintext = b"Hello, RC4 Cipher!" |
| 79 | + print(f"Original: {plaintext}") |
49 | 80 |
|
50 | | - ciphertext=rc4.encrypt(plaintext) |
51 | | - print("Encrypted:",ciphertext) |
| 81 | + ciphertext = rc4.encrypt(plaintext) |
| 82 | + print(f"Encrypted: {ciphertext}") |
52 | 83 |
|
53 | | - decrypted_text=rc4.decrypt(ciphertext) |
54 | | - print("Decrypted:",decrypted_text) |
55 | | - |
56 | | - assert plaintext==decrypted_text, "Decryption failed" |
| 84 | + decrypted_text = rc4.decrypt(ciphertext) |
| 85 | + print(f"Decrypted: {decrypted_text}") |
| 86 | + |
| 87 | + assert plaintext == decrypted_text, "Decryption failed!" |
57 | 88 | print("Encryption and decryption successful.") |
0 commit comments