71 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
from hashlib import sha3_256
 | 
						|
from itertools import count, islice
 | 
						|
from Crypto.Cipher import ChaCha20
 | 
						|
from math import floor, ceil
 | 
						|
from time import sleep
 | 
						|
from os import environ
 | 
						|
from sys import stderr
 | 
						|
 | 
						|
def debug(*args):
 | 
						|
    if 'DEBUG' in environ:
 | 
						|
        print(*args, file=stderr)
 | 
						|
 | 
						|
def chacha_bits(input, bit_count):
 | 
						|
    zerobyte = (0).to_bytes(length=1, byteorder='big')
 | 
						|
    cipher = ChaCha20.new(key=sha3_256(input).digest(), nonce=zerobyte*8)
 | 
						|
    i = 0
 | 
						|
 | 
						|
    while True:
 | 
						|
        debug(f'--- BITS {i} ---')
 | 
						|
        start_bit = bit_count * i
 | 
						|
        start_byte = start_bit // 8
 | 
						|
        start_padding = start_bit % 8
 | 
						|
        debug('start_bit', start_bit)
 | 
						|
        debug('start_byte', start_byte)
 | 
						|
        debug('start_padding', start_padding)
 | 
						|
 | 
						|
        end_bit = bit_count * i + bit_count
 | 
						|
        end_byte = end_bit // 8
 | 
						|
        end_padding = 8 - (end_bit % 8)
 | 
						|
        debug('end_bit', end_bit)
 | 
						|
        debug('end_byte', end_byte)
 | 
						|
        debug('end_padding', end_padding)
 | 
						|
        
 | 
						|
        byte_count = (end_byte - start_byte) + 1
 | 
						|
        debug('byte_count', byte_count)
 | 
						|
 | 
						|
        cipher.seek(start_byte)
 | 
						|
        cipherint = int.from_bytes(cipher.encrypt(zerobyte*byte_count), byteorder='big')
 | 
						|
        debug('ciphertext', bin(cipherint))
 | 
						|
        shifted_cipherint = cipherint >> end_padding
 | 
						|
        debug('shifted_ciphertext', bin(shifted_cipherint))
 | 
						|
        
 | 
						|
        bit_mask = int('1'*bit_count, 2)
 | 
						|
        debug('bit_mask', bin(bit_mask))
 | 
						|
        masked_cipherint = shifted_cipherint & bit_mask
 | 
						|
        debug('masked_ciphertext', bin(masked_cipherint))
 | 
						|
 | 
						|
        debug('')
 | 
						|
        yield masked_cipherint
 | 
						|
        i += 1
 | 
						|
 | 
						|
 | 
						|
def chacha_chracter(input, choices):
 | 
						|
    get_bits = chacha_bits(input, len(choices).bit_length())
 | 
						|
    
 | 
						|
    while True:
 | 
						|
        key = next(get_bits)
 | 
						|
        if key < len(choices):
 | 
						|
            yield choices[key]
 | 
						|
 | 
						|
 | 
						|
def derive_string(input, length, choices):
 | 
						|
    sorted_choices = bytes(sorted(choices))
 | 
						|
    get_character = chacha_chracter(input, sorted_choices)
 | 
						|
    return bytes(islice(get_character, length))
 | 
						|
 | 
						|
# print(
 | 
						|
#     derive_string(b'12344', length=100, choices=b'abcdefghijklmnopqrstuvwxyz0123456789')
 | 
						|
# )
 |