forked from oshynsong/web
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRailFence.py
169 lines (153 loc) · 5.64 KB
/
RailFence.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#encoding=utf-8
#+-------------------------------------------------------+
# RailFence.py
# Copyright (c) 2015 OshynSong<[email protected]>
#
# Encrypt/Decrypt the short text message by the rail fence
# cipher. Only surpport for ascii character.
#+-------------------------------------------------------+
'''
RailFence
This module contains the encrypt and decrypt for common
usage of rail fence cipher.
Usage:
>>> import RailFence
>>> obj = RailFence.RailFence([row=2[, mask=None]])
>>> obj.encrypt(src)
>>> obj.decrypt(dst)
or by directly usage
>>> RailFence.encrypt(src, [row=2[, mask=None]])
>>> RailFence.decrypt(dst, [row=2[, mask=None]])
'''
from __future__ import division
import string
import types
import math
CHARS = string.ascii_uppercase + string.ascii_lowercase
class RailFence:
'''The rail fence cipher class definition'''
def __init__(self, row = 2, mask = None):
if row < 2:
raise ValueError(u'Not acceptable row number or mask value')
self.Row = row
if mask != None and not isinstance(mask, (types.StringType, types.UnicodeType)):
raise ValueError(u'Not acceptable mask value')
self.Mask = mask
self.Length = 0
self.Column = 0
def encrypt(self, src, nowhitespace = False):
if not isinstance(src, (types.StringType, types.UnicodeType)):
raise TypeError(u'Encryption src text is not string')
if nowhitespace:
self.NoWhiteSpace = ''
for i in src:
if i in string.whitespace: continue
self.NoWhiteSpace += i
else:
self.NoWhiteSpace = src
self.Length = len(self.NoWhiteSpace)
self.Column = int(math.ceil(self.Length / self.Row))
try:
self.__check()
except Exception, msg:
print msg
#get mask order
self.__getOrder()
grid = [[] for i in range(self.Row)]
for c in range(self.Column):
endIndex = (c + 1) * self.Row
if endIndex > self.Length:
endIndex = self.Length
r = self.NoWhiteSpace[c * self.Row : endIndex]
for i,j in enumerate(r):
if self.Mask != None and len(self.Order) > 0:
grid[self.Order[i]].append(j)
else:
grid[i].append(j)
return ''.join([''.join(l) for l in grid])
def decrypt(self, dst):
if not isinstance(dst, (types.StringType, types.UnicodeType)):
raise TypeError(u'Decryption dst text is not string')
self.Length = len(dst)
self.Column = int(math.ceil(self.Length / self.Row))
try:
self.__check()
except Exception, msg:
print msg
#get mask order
self.__getOrder()
grid = [[] for i in range(self.Row)]
space = self.Row * self.Column - self.Length
ns = self.Row - space
prevE = 0
for i in range(self.Row):
if self.Mask != None:
s = prevE
O = 0
for x,y in enumerate(self.Order):
if i == y:
O = x
break
if O < ns: e = s + self.Column
else: e = s + (self.Column - 1)
r = dst[s : e]
prevE = e
grid[O] = list(r)
else:
startIndex = 0
endIndex = 0
if i < self.Row - space:
startIndex = i * self.Column
endIndex = startIndex + self.Column
else:
startIndex = ns * self.Column + (i - ns) * (self.Column - 1)
endIndex = startIndex + (self.Column - 1)
r = dst[startIndex:endIndex]
grid[i] = list(r)
res = ''
for c in range(self.Column):
for i in range(self.Row):
line = grid[i]
if len(line) == c:
res += ' '
else:
res += line[c]
return res
def __check(self):
#The length of column must be equal or bigger than 2
if self.Column < 2:
raise Error(u'Unexpected column number')
#The length of the mask must be equal to row
if self.Mask != None and len(self.Mask) != self.Row:
raise ValueError(u'Mask length not match, must be equal to row')
def __getOrder(self):
self.Order = []
if self.Mask != None:
maskOrder = []
for i in self.Mask:
maskOrder.append(CHARS.index(i))
ordered = sorted(maskOrder, reverse=False)
for i in range(self.Row):
now = maskOrder[i]
for j,k in enumerate(ordered):
if k == now:
self.Order.append(j)
break
def encrypt(src, row = 2, mask = None, nowhitespace = False):
rf = RailFence(row, mask)
return rf.encrypt(src, nowhitespace)
def decrypt(dst, row = 2, mask = None):
rf = RailFence(row, mask)
return rf.decrypt(dst)
def test():
print 'By directly method:'
e = encrypt('the anwser is wctf{C01umnar},if u is a big new,u can help us think more question,tks.', 4, 'bcaf', True)
print e
print decrypt(e, 4, 'bcaf')
print 'By class object:'
rf = RailFence(4, 'bcaf')
e = rf.encrypt('the anwser is wctf{C01umnar},if u is a big new,u can help us think more question,tks.')
print "Encrypt: ",e
print "Decrypt: ", rf.decrypt(e)
if __name__ == '__main__':
test()