11import hashlib , struct , base64
22
3- from pproxy .cipher import BaseCipher
3+ from pproxy .cipher import BaseCipher , AEADCipher
44
55# Pure Python Ciphers
66
@@ -62,8 +62,11 @@ def setup(self):
6262class ChaCha20_Cipher (StreamCipher ):
6363 KEY_LENGTH = 32
6464 IV_LENGTH = 8
65+ def __init__ (self , key , ota = False , setup_key = True , * , counter = 0 ):
66+ super ().__init__ (key , ota , setup_key )
67+ self .counter = counter
6568 def core (self ):
66- data = list (struct .unpack ('<16I' , b'expand 32-byte k' + self .key + self .iv .rjust (16 , b'\x00 ' )))
69+ data = list (struct .unpack ('<16I' , b'expand 32-byte k' + self .key + self .counter . to_bytes ( 4 , 'little' ) + self . iv .rjust (12 , b'\x00 ' )))
6770 ORDERS = ((0 ,4 ,8 ,12 ),(1 ,5 ,9 ,13 ),(2 ,6 ,10 ,14 ),(3 ,7 ,11 ,15 ),(0 ,5 ,10 ,15 ),(1 ,6 ,11 ,12 ),(2 ,7 ,8 ,13 ),(3 ,4 ,9 ,14 )) * 10
6871 while 1 :
6972 H = data [:]
@@ -82,6 +85,33 @@ def core(self):
8285class ChaCha20_IETF_Cipher (ChaCha20_Cipher ):
8386 IV_LENGTH = 12
8487
88+ def poly1305 (cipher_new , nonce , ciphertext ):
89+ otk = cipher_new (nonce ).encrypt (bytes (32 ))
90+ mac_data = ciphertext + bytes ((- len (ciphertext ))% 16 + 8 ) + len (ciphertext ).to_bytes (8 , 'little' )
91+ acc , r , s = 0 , int .from_bytes (otk [:16 ], 'little' ) & 0x0ffffffc0ffffffc0ffffffc0fffffff , int .from_bytes (otk [16 :], 'little' )
92+ for i in range (0 , len (mac_data ), 16 ):
93+ acc = (r * (acc + int .from_bytes (mac_data [i :i + 16 ]+ b'\x01 ' , 'little' ))) % ((1 << 130 )- 5 )
94+ return ((acc + s ) & ((1 << 128 )- 1 )).to_bytes (16 , 'little' )
95+
96+ class ChaCha20_IETF_POLY1305_Cipher (AEADCipher ):
97+ PYTHON = True
98+ KEY_LENGTH = 32
99+ IV_LENGTH = 32
100+ NONCE_LENGTH = 12
101+ TAG_LENGTH = 16
102+ def process (self , s , tag = None ):
103+ nonce = self .nonce
104+ if tag is not None :
105+ assert tag == poly1305 (self .cipher_new , nonce , s )
106+ data = self .cipher_new (nonce , counter = 1 ).encrypt (s )
107+ if tag is None :
108+ return data , poly1305 (self .cipher_new , nonce , data )
109+ else :
110+ return data
111+ encrypt_and_digest = decrypt_and_verify = process
112+ def setup (self ):
113+ self .cipher_new = lambda nonce , counter = 0 : ChaCha20_IETF_Cipher (self .key , setup_key = False , counter = counter ).setup_iv (nonce )
114+
85115class Salsa20_Cipher (StreamCipher ):
86116 KEY_LENGTH = 32
87117 IV_LENGTH = 8
@@ -135,7 +165,7 @@ def core_bit(self, segment_bit):
135165 next_iv = int .from_bytes (self .iv , 'big' )
136166 mask = (1 << self .IV_LENGTH * 8 ) - 1
137167 while 1 :
138- data = self .cipher .encrypt (next_iv . to_bytes ( self . IV_LENGTH , 'big' ) )
168+ data = self .cipher .encrypt (next_iv )
139169 next_iv = next_iv << segment_bit & mask
140170 for i in range (segment_bit ):
141171 next_iv |= (yield data [i // 8 ]>> (7 - i % 8 )& 1 )<< (segment_bit - 1 - i )
@@ -153,7 +183,7 @@ def setup(self):
153183 def core (self ):
154184 next_iv = int .from_bytes (self .iv , 'big' )
155185 while 1 :
156- yield from self .cipher .encrypt (next_iv . to_bytes ( self . IV_LENGTH , 'big' ) )
186+ yield from self .cipher .encrypt (next_iv )
157187 next_iv = 0 if next_iv >= (1 << (self .IV_LENGTH * 8 ))- 1 else next_iv + 1
158188
159189class OFBCipher (CTRCipher ):
@@ -163,6 +193,41 @@ def core(self):
163193 data = self .cipher .encrypt (data )
164194 yield from data
165195
196+ class GCMCipher (AEADCipher ):
197+ PYTHON = True
198+ NONCE_LENGTH = 12
199+ TAG_LENGTH = 16
200+ def setup (self ):
201+ self .cipher = self .CIPHER .new (self .key )
202+ self .hkey = []
203+ x = int .from_bytes (self .cipher .encrypt (0 ), 'big' )
204+ for i in range (128 ):
205+ self .hkey .insert (0 , x )
206+ x = (x >> 1 )^ (0xe1 << 120 ) if x & 1 else x >> 1
207+ def process (self , s , tag = None ):
208+ def multh (y ):
209+ z = 0
210+ for i in range (128 ):
211+ if y & (1 << i ):
212+ z ^= self .hkey [i ]
213+ return z
214+ def ghash (d ):
215+ dt = d + bytes ((- len (d ))% 16 )
216+ z = 0
217+ for i in range (0 , len (dt ), 16 ):
218+ z = multh (z ^ int .from_bytes (dt [i :i + 16 ], 'big' ))
219+ return multh (z ^ (len (d )* 8 ))
220+ z = int .from_bytes (self .nonce , 'big' )<< 32
221+ h = int .from_bytes (self .cipher .encrypt (z | 1 ), 'big' )
222+ if tag is not None :
223+ assert (ghash (s )^ h ).to_bytes (self .TAG_LENGTH , 'big' ) == tag
224+ ret = bytes (s [i * 16 + j ]^ o for i in range ((len (s )+ 15 )// 16 ) for j , o in enumerate (self .cipher .encrypt (z | (i + 2 )& ((1 << 32 )- 1 ))) if i * 16 + j < len (s ))
225+ if tag is None :
226+ return ret , (ghash (ret )^ h ).to_bytes (self .TAG_LENGTH , 'big' )
227+ else :
228+ return ret
229+ encrypt_and_digest = decrypt_and_verify = process
230+
166231class RAW :
167232 CACHE = {}
168233 @classmethod
@@ -191,15 +256,16 @@ def __init__(self, key):
191256 ekey .extend (m ^ ekey [i - size ] for i , m in enumerate (t ))
192257 self .ekey = tuple (ekey [i * 16 :i * 16 + 16 ] for i in range (nbr + 1 ))
193258 def encrypt (self , data ):
259+ data = data .to_bytes (16 , 'big' ) if isinstance (data , int ) else data
194260 s = [data [j ]^ self .ekey [0 ][j ] for j in range (16 )]
195261 for key in self .ekey [1 :- 1 ]:
196262 s = [self .g2 [s [a ]]^ self .g1 [s [b ]]^ self .g1 [s [c ]]^ self .g3 [s [d ]]^ key [j ] for j ,a ,b ,c ,d in self .shifts ]
197263 return bytes ([self .g1 [s [self .shifts [j ][1 ]]]^ self .ekey [- 1 ][j ] for j in range (16 )])
198264
199- for method in (CFBCipher , CFB8Cipher , CFB1Cipher , CTRCipher , OFBCipher ):
265+ for method in (CFBCipher , CFB8Cipher , CFB1Cipher , CTRCipher , OFBCipher , GCMCipher ):
200266 for key in (32 , 24 , 16 ):
201267 name = 'AES_{}_{}_Cipher' .format (key * 8 , method .__name__ [:- 6 ])
202- globals ()[name ] = type (name , (method ,), dict (KEY_LENGTH = key , IV_LENGTH = 16 , CIPHER = AES ))
268+ globals ()[name ] = type (name , (method ,), dict (KEY_LENGTH = key , IV_LENGTH = key if method is GCMCipher else 16 , CIPHER = AES ))
203269
204270class Blowfish (RAW ):
205271 P = None
@@ -220,6 +286,7 @@ def __init__(self, key):
220286 buf = self .encrypt (buf )
221287 self .p [i :i + 2 ] = struct .unpack ('>II' , buf )
222288 def encrypt (self , s ):
289+ s = data .to_bytes (8 , 'big' ) if isinstance (s , int ) else s
223290 sl , sr = struct .unpack ('>II' , s )
224291 sl ^= self .p [0 ]
225292 for i in self .p [1 :17 ]:
@@ -250,7 +317,7 @@ def __init__(self, key):
250317 e = [(q [n ]<< m >> o | q [n ]>> 128 - m + o )& (1 << 64 )- 1 for n , m , o in ks ]
251318 self .e = [e [i + i // 7 ]<< 64 | e [i + i // 7 + 1 ] if i % 7 == 0 else e [i + i // 7 + 1 ] for i in range (nr )]
252319 def encrypt (self , s ):
253- s = int .from_bytes (s , 'big' )^ self .e [0 ]
320+ s = ( s if isinstance ( s , int ) else int .from_bytes (s , 'big' ) )^ self .e [0 ]
254321 for idx , k in enumerate (self .e [1 :- 1 ]):
255322 s = s ^ ((s & k )>> 95 & 0xfffffffe | (s & k )>> 127 )<< 64 ^ ((s & k )<< 1 & ~ 1 << 96 ^ (s & k )>> 31 ^ s << 32 | k << 32 )& 0xffffffff << 96 ^ ((s | k )& 0xffffffff )<< 32 ^ ((s | k )<< 1 ^ s >> 31 )& k >> 31 & 0xfffffffe ^ ((s | k )>> 31 ^ s >> 63 )& k >> 63 & 1 if (idx + 1 )% 7 == 0 else self .R (s , k )
256323 return (s >> 64 ^ (s & (1 << 64 )- 1 )<< 64 ^ self .e [- 1 ]).to_bytes (16 , 'big' )
@@ -273,6 +340,7 @@ def __init__(self, key):
273340 e .append ((e [i - 8 & 0xf8 | i + 1 & 0x7 ]& 0x7f )<< 9 | e [i - 8 & 0xf8 | i + 2 & 0x7 ]>> 7 )
274341 self .e = [e [i * 6 :i * 6 + 6 ] for i in range (9 )]
275342 def encrypt (self , s ):
343+ s = data .to_bytes (8 , 'big' ) if isinstance (s , int ) else s
276344 M = lambda a ,b : (a * b - (a * b >> 16 )+ (a * b & 0xffff < a * b >> 16 ) if a else 1 - b if b else 1 - a )& 0xffff
277345 s0 , s1 , s2 , s3 = struct .unpack ('>4H' , s )
278346 for e in self .e [:- 1 ]:
@@ -299,6 +367,7 @@ def __init__(self, key):
299367 self .e .append ((self .G ((key0 >> 32 )+ (key1 >> 32 )- kc ), self .G (key0 - key1 + kc )))
300368 key0 , key1 = (key0 , (key1 << 8 | key1 >> 56 )& (1 << 64 )- 1 ) if i & 1 else ((key0 << 56 | key0 >> 8 )& (1 << 64 )- 1 , key1 )
301369 def encrypt (self , s ):
370+ s = data .to_bytes (16 , 'big' ) if isinstance (s , int ) else s
302371 s0 , s1 , s2 , s3 = struct .unpack ('>4I' , s )
303372 for k0 , k1 in self .e :
304373 t0 = self .G (s2 ^ k0 ^ s3 ^ k1 )
@@ -324,6 +393,7 @@ def __init__(self, key):
324393 e [i ] = self .S [e [i + 1 ]^ e [i + len (key )]]
325394 self .e = struct .unpack ('<64H' , e )
326395 def encrypt (self , s ):
396+ s = data .to_bytes (8 , 'big' ) if isinstance (s , int ) else s
327397 s = list (struct .unpack ('<4H' , s ))
328398 for j in self .B :
329399 s [j & 3 ] = s [j & 3 ]+ self .e [j ]+ (s [j + 3 & 3 ]& s [j + 2 & 3 ])+ (~ s [j + 3 & 3 ]& s [j + 1 & 3 ])<< j % 4 * 4 // 3 + 1 & 0xffff | (s [j & 3 ]+ self .e [j ]+ (s [j + 3 & 3 ]& s [j + 2 & 3 ])+ (~ s [j + 3 & 3 ]& s [j + 1 & 3 ])& 0xffff )>> 15 - j % 4 * 4 // 3 if j >= 0 else s [j ]+ self .e [s [j + 3 ]& 0x3f ]
0 commit comments