本示例DRNG设计参考了GM/T 0105 ,基于SM3算法实现,内部功能接口包括初始化函数、重播种函数、输出函数和已知答案自测试函数,同时还具备DRNG内部状态和错误状态两种内部工作状态。整体框图如下图所示。
内部状态包括{V, C, reseed_counter, last_reseed_time, reseed_counter_interval, reseed_time_interval },定义如下:
——比特串V,长度为440比特,每次随机数生成时会进行更新;
——比特串C,长度为440,每次重播种时会进行更新;
——reseed_counter, 在初始化或重播种之后,请求随机数的次数,每次执行随机数生成操作时会加1;
——last_reseed_time,上次重播种的时间值,Unix 时间戳,单位为秒;
——reseed_counter_interval,重播种计数器阈值,该值为常量值1024;
——reseed_time_interval,重播种时间阈值,单位为秒,该值为常量值60s。
初始化函数中利用熵源数据对初始状态进行赋值,包含变量初始化和初始化种子函数:
SM3_RNG_Instantiate(nonce)
输入:
——entropy_input:从熵池获取熵压缩函数处理后的结果,长度为440比特。
——nonce: 系统启动时间、当前时间戳、递增计数器信息和固定的随机比特串。
输出:
——初始化内部状态,即V, C, reseed_counter, last_reseed_time, reseed_counter_interval, reseed_time_interval的初始值。
Nonce包括系统启动时间、当前时间戳、递增计数器信息和固定的随机比特串。如下表所示。
熵源 | 说明 | 长度(字节) |
---|---|---|
CPU信息 | 系统时间(精确到微妙) | 4 |
时间信息 | UTC时间信息(精确到纳秒) | 4 |
递增计数器 | 每次调用增1 | 4 |
固定随机值 | 产生自真随机数发生器的随机数 | 128 |
初始化流程如下:
a) 获取440比特的熵输入entropy_input;
b) 生成种子seed = SM3_df(entropy_input || nonce, seedlen)。Seedlen为440比特;
c) 初始化内部状态变量,包括V、C、reseed_counter。其中V = seed,C = SM3_df (0x00||V, seedlen),reseed_counter = 1;
d) 返回内部状态变量。
#generate nonce
def RNG_Gen_Nonce():
global nonce_counter
boottime = (int(psutil.boot_time()) & 0xFFFFFFFF).to_bytes(4, byteorder = 'big', signed=False)
timestamp = (int(time_ns()) & 0xFFFFFFFF).to_bytes(4, byteorder = 'big', signed=False)
counterbytes = nonce_counter.to_bytes(4, byteorder = 'big', signed=False)
fixrandom = bytes.fromhex("331051e42be3c2139b4077728785ff2553d1d7ffc7c98377875581837ee6a99501bd28a12c491ea656e5666286fdabc56bb05d811596e9667b165367c7d2e4c8")
nonce_counter += 1
return boottime + timestamp + counterbytes + fixrandom
def SM3_RNG_Instantiate(nonce):
global min_length
global max_length
# min_entropy = min_length
while True:
(status, entropy_input) = Get_entropy (256, min_length, max_length)
if status == -2:#need time to generate entropy
continue
if status != 0:
print('entropy source error! please check system source.')
return -1
break
seed = SM3_df(entropy_input + nonce, seedlen)
reseed_counter = 1
return Working_state(seed, SM3_df ((bytes([0x00])+ seed), seedlen), reseed_counter)
def Get_entropy (min_entropy, min_length, max_length):
global drngentropy
global drngentropylock
#compress functiong output is about 340*8bits
if min_entropy > 340*8:#min entropy is too big
return (-1, bytes())
drngentropylock.acquire()
#drngentropy is 440 bits fixed, min_length is not expected bigger than 440
if min_length > (len(drngentropy)*8):#need time to generate entropy
drngentropylock.release()
return (-2, bytes())
#retdrngentropy is the var to return
retdrngentropy = drngentropy
#clear drngentropy
drngentropy = bytes()
drngentropylock.release()
# print('main thread get entropy OK----')
return (0,retdrngentropy)
SM3_df在软件随机数发生器的初始化和重播种阶段使用,对输入字符串进行杂凑运算,并返回请求的随机比特串。定义如下:
函数定义: SM3_df(input_string, no_of_bits_to_return)
输入:
——input_ string:输入字符串
——number_of_bits_to_return:SM3_df函数返回的比特长度
输出:
requested_bits:SM3_df函数返回的结果。
SM3_df函数作为扩展函数,实现流程如下。
1) 根据输入的返回数据长度(实际为440比特)和输出数据长度256比特计算循环次数。计算循环次数时使用向上取整方式。
2) 对计数器赋初值1,对临时数据赋初值空。
3) 计算SM3(计数器值||返回数据长度||输入熵源数据)。
4) 临时数据更新为临时数据||SM3结果。
5) 计数器增1。
6) 判断循环是否结果,若结束则跳转至第7步,否则跳转至第3步。
7) 取临时数据左侧指定长度数据,返回。
def sm3Hash(hashbytes:bytes):
temp = sm3_hash([i for i in hashbytes])
return bytes.fromhex(temp)
def SM3_df(input_string, no_of_bits_to_return):
temp = bytes([])
len = math.ceil(no_of_bits_to_return/outlen)
counter = 0x01
for i in range(len):
temp = temp + sm3Hash(bytes([counter]) + no_of_bits_to_return.to_bytes(4, 'big') + input_string)
counter = counter + 1
return temp[0:int(no_of_bits_to_return/8)]
随机数发生器中的重播种函数函数、输出函数、自测试函数放在下篇文章介绍。
如果商用密码产品认证中遇到问题,欢迎加微信symmrz或13720098215沟通。