@@ -334,3 +334,101 @@ def sha256_encrypt(text) -> str:
334334            h  =  [(x  +  y ) &  0xFFFFFFFF  for  x , y  in  zip (h , [a , b , c , d , e , f , g , h0 ])]
335335
336336        return  '' .join (f'{ value :08x}  '  for  value  in  h )
337+ 
338+     @staticmethod  
339+     def  yield_chacha20_xor_stream (key , iv , position = 0 ):
340+         """Generate the xor stream with the ChaCha20 cipher.""" 
341+         if  not  isinstance (position , int ):
342+             raise  TypeError 
343+         if  position  &  ~ 0xFFFFFFFF :
344+             raise  ValueError ("Position is not uint32." )
345+         if  not  isinstance (key , bytes ):
346+             raise  TypeError 
347+         if  not  isinstance (iv , bytes ):
348+             raise  TypeError 
349+         if  len (key ) !=  32 :
350+             raise  ValueError 
351+         if  len (iv ) !=  8 :
352+             raise  ValueError 
353+ 
354+         def  rotate (v , c ):
355+             return  ((v  <<  c ) &  0xFFFFFFFF ) |  v  >>  (32  -  c )
356+ 
357+         def  quarter_round (x , a , b , c , d ):
358+             x [a ] =  (x [a ] +  x [b ]) &  0xFFFFFFFF 
359+             x [d ] =  rotate (x [d ] ^  x [a ], 16 )
360+             x [c ] =  (x [c ] +  x [d ]) &  0xFFFFFFFF 
361+             x [b ] =  rotate (x [b ] ^  x [c ], 12 )
362+             x [a ] =  (x [a ] +  x [b ]) &  0xFFFFFFFF 
363+             x [d ] =  rotate (x [d ] ^  x [a ], 8 )
364+             x [c ] =  (x [c ] +  x [d ]) &  0xFFFFFFFF 
365+             x [b ] =  rotate (x [b ] ^  x [c ], 7 )
366+ 
367+         ctx  =  [0 ] *  16 
368+         ctx [:4 ] =  (1634760805 , 857760878 , 2036477234 , 1797285236 )
369+         ctx [4 :12 ] =  struct .unpack ("<8L" , key )
370+         ctx [12 ] =  ctx [13 ] =  position 
371+         ctx [14 :16 ] =  struct .unpack ("<LL" , iv )
372+         while  1 :
373+             x  =  list (ctx )
374+             for  i  in  range (10 ):
375+                 quarter_round (x , 0 , 4 , 8 , 12 )
376+                 quarter_round (x , 1 , 5 , 9 , 13 )
377+                 quarter_round (x , 2 , 6 , 10 , 14 )
378+                 quarter_round (x , 3 , 7 , 11 , 15 )
379+                 quarter_round (x , 0 , 5 , 10 , 15 )
380+                 quarter_round (x , 1 , 6 , 11 , 12 )
381+                 quarter_round (x , 2 , 7 , 8 , 13 )
382+                 quarter_round (x , 3 , 4 , 9 , 14 )
383+             for  c  in  struct .pack (
384+                 "<16L" , * ((x [i ] +  ctx [i ]) &  0xFFFFFFFF  for  i  in  range (16 ))
385+             ):
386+                 yield  c 
387+             ctx [12 ] =  (ctx [12 ] +  1 ) &  0xFFFFFFFF 
388+             if  ctx [12 ] ==  0 :
389+                 ctx [13 ] =  (ctx [13 ] +  1 ) &  0xFFFFFFFF 
390+ 
391+     @staticmethod  
392+     def  chacha20 (data :bytes , key :bytes , nonce = None , position = 0 ):
393+         """ 
394+         Encrypt (or decrypt) data using the ChaCha20 stream cipher. 
395+ 
396+         Parameters 
397+         ========== 
398+         data : bytes 
399+             Input data to encrypt/decrypt 
400+         key : bytes 
401+             32-byte encryption key. Shorter keys will be padded by repetition. 
402+         nonce : bytes, optional 
403+             8-byte nonce 
404+ 
405+         Returns 
406+         ======= 
407+         bytes 
408+             Processed output 
409+ 
410+         Notes 
411+         ===== 
412+         Chacha20 is symmetric - same operation encrypts and decrypts. 
413+ 
414+         References 
415+         ========== 
416+ 
417+         .. [1] https://en.wikipedia.org/wiki/ChaCha20-Poly1305 
418+         .. [2] https://github.com/pts/chacha20/blob/master/chacha20_python3.py 
419+ 
420+         """ 
421+ 
422+         if  nonce  is  None :
423+             nonce  =  b"\0 "  *  8 
424+ 
425+         if  not  key :
426+             raise  ValueError ("Key is empty." )
427+         if  len (key ) <  32 :
428+             key  =  (key  *  (32  //  len (key ) +  1 ))[:32 ]
429+         if  len (key ) >  32 :
430+             key  =  key [:32 ]
431+ 
432+         return  bytes (
433+             a  ^  b  for  a , b  in  zip (data , Crypto .yield_chacha20_xor_stream (key , nonce , position ))
434+         )
0 commit comments