import secrets import time from gmssl.sm4 import CryptSM4,SM4_ENCRYPT import binascii class SM4_RNG: def __init__(self,personalization_string :bytes = b"",nonce:bytes = b""): self.keylen= 16 self.reseed_counter = 0 self.reseed_interval_in_counter = 1<<30 self.reseed_interval_in_time = 6000 self.min_entropy_input_length = 32 self.max_ectropy_input_length = 1<<35 - 1 self.seedlen = 32 self.outlen = 16 self.blocklen = 16 self.seed_material = "" self.sm4 = CryptSM4() self.SM4_RNG_Instantiate(personalization_string,nonce) def SM4_RNG_Instantiate(self,personalization_string :bytes = b"",nonce:bytes = b""): self.min_entropy = self.min_entropy_input_length self.entropy_input = secrets.token_bytes(self.min_entropy) self.seed_material = self.entropy_input + nonce + personalization_string self.seed_material = self.SM4_df(self.seed_material,self.seedlen) self.Key = b"\x00" * self.keylen self.V = b"\x00" * self.blocklen self.SM4_RNG_Update(self.seed_material,self.Key,self.V) self.reseed_counter = 1 self.last_reseed_time = int(time.time()) def SM4_RNG_Update(self,seed_material,Key,V): temp = b"" self.sm4.set_key(Key,SM4_ENCRYPT) while(len(temp) < self.seedlen): V = (int.from_bytes(V,"big") + 1) % (1< self.reseed_interval_in_counter or int(time.time()) - self.last_reseed_time > self.reseed_interval_in_time: self.SM4_RNG_Reseed(additional_input) if additional_input != b"": additional_input = self.SM4_df(additional_input,self.seedlen) self.SM4_RNG_Update(additional_input,self.Key,self.V) else: additional_input = b"\x00" * self.seedlen self.sm4.set_key(self.Key,SM4_ENCRYPT) while(len(returned_bits) < length): self.V = int.from_bytes(self.V,"big") + 1 % (1<