-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcryptoquail.py
125 lines (113 loc) · 3.78 KB
/
cryptoquail.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
# CryptoQuail Block Cipher
from itertools import cycle
import math
import hashlib, base64
def keygen(key):
h = hashlib.sha256()
h.update(key.encode())
return base64.a85encode(h.digest()).decode()[:24]
def rail_pattern(n):
r = list(range(n))
return cycle(r + r[-2:0:-1])
def encode(plaintext, rails):
p = rail_pattern(rails)
return ''.join(sorted(plaintext, key=lambda i: next(p)))
def decode(ciphertext, rails):
p = rail_pattern(rails)
indexes = sorted(range(len(ciphertext)), key=lambda i: next(p))
result = [''] * len(ciphertext)
for i, c in zip(indexes, ciphertext):
result[i] = c
return ''.join(result)
######
def text2number(string__, x):
if ord(string__[-1]) % 2 == 1:
string__ = string__[::-1]
return (int.from_bytes(string__.encode(), "little") % x) + 2
def modEncrypt(msg, key):
return "".join([chr((ord(msg[i]) + ord(key[i % len(key)])) % 256) for i in range(len(msg))])
def modDecrypt(cip, key):
return "".join([chr((ord(cip[i]) + (256 - ord(key[i % len(key)]))) % 256)for i in range(len(cip))])
######
def xor(s, k):
return "".join([chr(ord(f) ^ ord(k[i%len(k)])) for i, f in enumerate(s)])
######
def split(seq):
n = 12 # block length is 12
datas = []
while seq:
datas.append(seq[:n])
seq = seq[n:]
return datas
def pad(e):
if len(e) == 12: return e
else:
return e + (chr(0) * (12 - len(e)))
######
def encrypt(string, key):
"""
Encrypts the string with CryptoQuail.
For better security, encrypt the string 3 times.
"""
string = chr(len(string)) + string
string = modEncrypt(string, key)
ciphertext = ""
odometer = [1, 2, 3, 4]
blocks = split(string)
key1 = key[12:24]
key = key[:12]
for block in blocks:
block = pad(block)
if odometer[0] == 1:
for i in range(4):
block = modEncrypt(block, key1)
block = xor(block, key)
elif odometer[1] == 1:
for i in range(3):
block = xor(block, key)
block = modEncrypt(block, key)
elif odometer[2] == 1:
for i in range(2):
block = xor(block, key1)
block = modEncrypt(block, key1)
elif odometer[3] == 1:
block = modEncrypt(block, key1)
block = xor(block, key1)
odometer = odometer[1:] + [odometer[0]]
ciphertext = ciphertext + block
ciphertext = encode(ciphertext, text2number(key, 12))
return xor(ciphertext, chr(text2number(key1, 127)) + chr(text2number(key, 127)))
def decrypt(cipher, key):
string = ""
odometer = [1, 2, 3, 4]
key1 = key[12:24]
key = key[:12]
cipher = xor(cipher, chr(text2number(key1, 127)) + chr(text2number(key, 127)))
cipher = decode(cipher, text2number(key, 12))
blocks = split(cipher)
for block in blocks:
if odometer[1] == 1:
for i in range(3):
block = modDecrypt(block, key)
block = xor(block, key)
elif odometer[0] == 1:
for i in range(4):
block = xor(block, key)
block = modDecrypt(block, key1)
elif odometer[3] == 1:
block = xor(block, key1)
block = modDecrypt(block, key1)
elif odometer[2] == 1:
for i in range(2):
block = modDecrypt(block, key1)
block = xor(block, key1)
odometer = odometer[1:] + [odometer[0]]
string = string + block
final = list(modDecrypt(string, key + key1).rstrip())
char = ord(final.pop(0))
return "".join(final[:char])
if __name__ == "__main__":
a = encrypt("The quick brown fox jumped over the lazy dogs.", "abcdefghijkl12345678!@#$")
print(a)
b = decrypt(a, "abcdefghijkl12345678!@#$")
print(b)