from Crypto.Cipher import AES import secrets import time import binascii # 引入hexlify方法 class AES_CTR_DRBG: def __init__(self, personalization_string: bytes = b"", nonce: bytes = b""): self.keylen = 16 # AES密钥长度为128比特 self.blocklen = 16 # AES块大小为128比特 self.seedlen = 32 # 种子长度为256比特 self.outlen = 16 # 输出长度为128比特 # 重播种计数器,表明自初始化或者重播种期间获得新的熵输入依赖,请求随机数生成的次数 self.reseed_counter = 0 # 重播种计数器阈值,在重播种之前能够产生随机数的最大请求次数 # level 1 2^20次 # level 2 2^10次 self.reseed_interval_in_counter = 1 << 30 # 重播种时间阈值,距离上一次重播种的最大时间间隔,单位 秒 # level 1 600s # level 2 60s self.reseed_interval_in_time = 6000 # 最小的熵输入长度 self.min_entropy_input_length = 32 # 256比特 # 最大的熵输入长度 self.max_ectropy_input_length = 1 << 35 - 1 # 2^35比特 self.seed_material = b"" self.aes = AES.new(b"\x00" * self.keylen, AES.MODE_ECB) self.AES_CTR_DRBG_Instantiate(personalization_string, nonce) def AES_CTR_DRBG_Instantiate( self, personalization_string: bytes = b"", nonce: bytes = b"" )-> None: self.min_entropy = self.seedlen self.entropy_input = secrets.token_bytes(self.min_entropy) self.seed_material = self.entropy_input + nonce + personalization_string self.seed_material = self.AES_CTR_DRBG_df(self.seed_material, self.seedlen) self.Key = self.seed_material[: self.keylen] self.V = self.seed_material[-self.blocklen :] self.reseed_counter = 1 self.last_reseed_time = int(time.time()) def AES_CTR_DRBG_Update(self, seed_material:bytes, Key:bytes, V: bytes)->None: temp = b"" while len(temp) < len(seed_material): V_int = (int.from_bytes(self.V, "big") + 1) % (1 << (8 * self.blocklen)) self.V = V_int.to_bytes(self.blocklen, "big") temp += self.aes.encrypt(self.V) temp = temp[: len(seed_material)] temp = int.from_bytes(temp, "big") ^ int.from_bytes(seed_material, "big") temp = temp.to_bytes(len(seed_material), "big") self.Key = temp[: self.keylen] self.V = temp[-self.blocklen :] def AES_CTR_DRBG_df(self, input_string: bytes, number_of_bits_to_return: int): L = len(input_string).to_bytes(4, "big") N = number_of_bits_to_return.to_bytes(4, "big") S = L + N + input_string + b"\x80" while len(S) % self.blocklen != 0: S += b"\x00" temp = b"" i = 0 K = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"[ : self.keylen ] while len(temp) < self.keylen + self.outlen: IV = i.to_bytes(4, "big") + b"\x00" * (self.blocklen - 4) temp += self.CBC_MAC(K, IV + S) i += 1 K = temp[: self.keylen] X = temp[self.keylen : self.keylen + self.outlen] tmp = b"" while len(tmp) < number_of_bits_to_return: X = self.aes.encrypt(X) tmp += X requested_bits = tmp[:number_of_bits_to_return] return requested_bits def CBC_MAC(self, Key: bytes, data_to_MAC:bytes)->bytes: chaining_value = b"\x00" * self.blocklen for i in range(0, len(data_to_MAC), self.blocklen): block = data_to_MAC[i : i + self.blocklen] input_block = int.from_bytes(chaining_value, "big") ^ int.from_bytes( block, "big" ) chaining_value = self.aes.encrypt( input_block.to_bytes(self.blocklen, "big") ) return chaining_value def AES_CTR_DRBG_Reseed(self, additional_input: bytes)-> None: self.min_entropy = self.seedlen self.entropy_input = secrets.token_bytes(self.min_entropy) self.seed_material = self.entropy_input + additional_input self.seed_material = self.AES_CTR_DRBG_df(self.seed_material, self.seedlen) self.AES_CTR_DRBG_Update(self.seed_material, self.Key, self.V) self.reseed_counter = 1 self.last_reseed_time = int(time.time()) def AES_CTR_DRBG_Generate( self, requested_number_of_bits: int, additional_input: bytes = b"" )-> bytes: length = requested_number_of_bits // 8 returned_bits = b"" if ( self.reseed_counter > (1 << 48) or int(time.time()) - self.last_reseed_time > 600 ): self.AES_CTR_DRBG_Reseed(additional_input) if additional_input != b"": additional_input = self.AES_CTR_DRBG_df(additional_input, self.seedlen) self.AES_CTR_DRBG_Update(additional_input, self.Key, self.V) else: additional_input = b"\x00" * self.seedlen while len(returned_bits) < length: V_int = (int.from_bytes(self.V, "big") + 1) % (1 << (8 * self.blocklen)) self.V = V_int.to_bytes(self.blocklen, "big") output_block = self.aes.encrypt(self.V) returned_bits += output_block self.AES_CTR_DRBG_Update(additional_input, self.Key, self.V) self.reseed_counter += 1 return returned_bits[:length] if __name__ == "__main__": bit_len = int(input("Enter the length of the bit string to be generated(bit):")) num = int(input("Enter the number of the bit string to be generated:")) file_name = input("Enter the name of the saved file:") start_time = time.time() # 记录开始时间 aesDrbg = AES_CTR_DRBG() with open(file_name, "w") as f: # 改为以文本方式写入 for i in range(num): hex_output = binascii.hexlify( aesDrbg.AES_CTR_DRBG_Generate(bit_len) ).decode() # 转为十六进制并解码为string f.write(hex_output + "\n") # 在每次写入后换行 end_time = time.time() # 记录结束时间 elapsed_time = end_time - start_time # 计算经过的时间 print(f"running time: {elapsed_time} ") # 打印出运行时间