forked from manojpandey/rc4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rc4-3.py
154 lines (125 loc) · 4.16 KB
/
rc4-3.py
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: @manojpandey
# Python 3 implementation for RC4 algorithm
# Brief: https://en.wikipedia.org/wiki/RC4
# Will use codecs, as 'str' object in Python 3 doesn't have any attribute 'decode'
import codecs
MOD = 256
def KSA(key):
''' Key Scheduling Algorithm (from wikipedia):
for i from 0 to 255
S[i] := i
endfor
j := 0
for i from 0 to 255
j := (j + S[i] + key[i mod keylength]) mod 256
swap values of S[i] and S[j]
endfor
'''
key_length = len(key)
# create the array "S"
S = list(range(MOD)) # [0,1,2, ... , 255]
j = 0
for i in range(MOD):
j = (j + S[i] + key[i % key_length]) % MOD
S[i], S[j] = S[j], S[i] # swap values
return S
def PRGA(S):
''' Psudo Random Generation Algorithm (from wikipedia):
i := 0
j := 0
while GeneratingOutput:
i := (i + 1) mod 256
j := (j + S[i]) mod 256
swap values of S[i] and S[j]
K := S[(S[i] + S[j]) mod 256]
output K
endwhile
'''
i = 0
j = 0
while True:
i = (i + 1) % MOD
j = (j + S[i]) % MOD
S[i], S[j] = S[j], S[i] # swap values
K = S[(S[i] + S[j]) % MOD]
yield K
def get_keystream(key):
''' Takes the encryption key to get the keystream using PRGA
return object is a generator
'''
S = KSA(key)
return PRGA(S)
def encrypt_logic(key, text):
''' :key -> encryption key used for encrypting, as hex string
:text -> array of unicode values/ byte string to encrpyt/decrypt
'''
# For plaintext key, use this
key = [ord(c) for c in key]
# If key is in hex:
# key = codecs.decode(key, 'hex_codec')
# key = [c for c in key]
keystream = get_keystream(key)
res = []
for c in text:
val = ("%02X" % (c ^ next(keystream))) # XOR and taking hex
res.append(val)
return ''.join(res)
def encrypt(key, plaintext):
''' :key -> encryption key used for encrypting, as hex string
:plaintext -> plaintext string to encrpyt
'''
plaintext = [ord(c) for c in plaintext]
return encrypt_logic(key, plaintext)
def decrypt(key, ciphertext):
''' :key -> encryption key used for encrypting, as hex string
:ciphertext -> hex encoded ciphered text using RC4
'''
ciphertext = codecs.decode(ciphertext, 'hex_codec')
res = encrypt_logic(key, ciphertext)
return codecs.decode(res, 'hex_codec').decode('utf-8')
def main():
key = 'not-so-random-key' # plaintext
plaintext = 'Good work! Your implementation is correct' # plaintext
# encrypt the plaintext, using key and RC4 algorithm
ciphertext = encrypt(key, plaintext)
print('plaintext:', plaintext)
print('ciphertext:', ciphertext)
# ..
# Let's check the implementation
# ..
ciphertext = '2D7FEE79FFCE80B7DDB7BDA5A7F878CE298615'\
'476F86F3B890FD4746BE2D8F741395F884B4A35CE979'
# change ciphertext to string again
decrypted = decrypt(key, ciphertext)
print('decrypted:', decrypted)
if plaintext == decrypted:
print('\nCongrats ! You made it.')
else:
print('Shit! You pooped your pants ! .-.')
# until next time folks !
def test():
# Test case 1
# key = '4B6579' # 'Key' in hex
# key = 'Key'
# plaintext = 'Plaintext'
# ciphertext = 'BBF316E8D940AF0AD3'
assert(encrypt('Key', 'Plaintext')) == 'BBF316E8D940AF0AD3'
assert(decrypt('Key', 'BBF316E8D940AF0AD3')) == 'Plaintext'
# Test case 2
# key = 'Wiki' # '57696b69'in hex
# plaintext = 'pedia'
# ciphertext should be 1021BF0420
assert(encrypt('Wiki', 'pedia')) == '1021BF0420'
assert(decrypt('Wiki', '1021BF0420')) == 'pedia'
# Test case 3
# key = 'Secret' # '536563726574' in hex
# plaintext = 'Attack at dawn'
# ciphertext should be 45A01F645FC35B383552544B9BF5
assert(encrypt('Secret',
'Attack at dawn')) == '45A01F645FC35B383552544B9BF5'
assert(decrypt('Secret',
'45A01F645FC35B383552544B9BF5')) == 'Attack at dawn'
if __name__ == '__main__':
main()