"""
Author: tanglei
DateTime:2024-11-18 完成
微信:ciss_cedar
欢迎一起学习
"""
import re
from datetime import datetime
from sm3_apply import sm3_hash
#key 16进制 16字节密钥
#T-参与运算的时间因子(5.2.1的计算结果);
#C-参与运算的事件因子,表示为一个4字节整数; 2^32
#Q --鉴别双方通过协商输入的挑战因子(或其他类型参与运算的因子),使用ASCII码表示
#N 动态口令长度最小为6
#Period otp 周期,60代表60秒有效
def gen_otp(Key,T,C,Q,N,Period=60):
"""
:param key:key 16进制 16字节密钥
:param T:T-参与运算的时间因子,传入当前时间
:param C:参与运算的事件因子,表示为一个4字节整数; 2^32,
:param Q:鉴别双方通过协商输入的挑战因子可以和平台协调一个随机数
:param N:动态口令长度最小为6
:param Period:otp 周期,60代表60秒有效
:return:
"""
t = calculate_t(T,Period)
id = calculate_id(t,C,Q)
s = calculate_s(Key, id)
od = calculate_od(s)
p = calculate_p(od,N)
return p
def calculate_t(input_time:datetime,Period=60):
# 获取当前时间的UTC秒数(从某个固定时间点,通常是1970年1月1日00:00:00开始)
c_seconds=input_time.timestamp()
c_seconds=int(c_seconds)
# 由于我们只需要一个周期内的递增值,我们可以对当前时间秒数进行模运算
# 这里我们假设period是60秒或30秒等,确保它不大于60秒
t = c_seconds // Period # 使用整除来获取当前周期内的“序号”
# 如果需要,可以对time_factor进行进一步处理,比如转换为8字节整数格式(这里简单返回)
return t
def calculate_id(T=None, C=None, Q=None):
if C is not None and len(str(C))==0:
C=None
if Q is not None and len(str(Q))==0:
Q=None
if T is None and C is None:
raise ValueError("At least one of T or C must be provided.")
# Convert integers to byte representation
if C is not None:
C_bytes = C.to_bytes(4, 'big') # 4 bytes for a 32-bit integer
else:
C_bytes = b''
# Ensure Q is a string and contains at least 4 characters
if Q is not None:
if not isinstance(Q, str) or len(Q) < 4:
raise ValueError("Q must be a string with at least 4 characters.")
# Convert Q to byte representation using ASCII
#将难以识别的字符(例如空格)或容易混淆的字符(例如数字1和字母1、数字0和字母O、字符’和字符、。替换为空字符
pattern = re.compile(r"[ 1I0O'、]", flags=re.IGNORECASE)
Q = pattern.sub('', Q)
Q_bytes = Q.encode('ascii')
else:
Q_bytes = b''
# Convert T to byte representation (assuming it's a string and using UTF-8 encoding)
if T is not None:
T=str(T)
T_bytes = T.encode('utf-8')
else:
T_bytes = b''
# Combine the bytes
combined_bytes = T_bytes + C_bytes + Q_bytes
# Pad with '0' (null bytes) to ensure the length is at least 16 bytes (128 bits)
while len(combined_bytes) < 16:
combined_bytes += b'\x00'
# Ensure the length is exactly 16 bytes by truncating if necessary
id = combined_bytes[:16]
# Convert the final byte sequence back to a hexadecimal string for easy viewing (optional)
# final_hex = combined_bytes.hex()
return id
def calculate_s(key,id):
key=bytes.fromhex(key)
input=key+id
input=input.hex()
s=sm3_hash(input)
return s
def calculate_od(s:str):
"""
8个整数相加,并截断为32比特。
"""
# 计算8个整数的和
s1 = int(s[0:8],16)
s2 = int(s[8:16],16)
s3 = int(s[16:24],16)
s4 = int(s[24:32],16)
s5 = int(s[32:40],16)
s6 = int(s[40:48],16)
s7 = int(s[48:56],16)
s8 = int(s[56:64],16)
sum_s = s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8
# 截断为32比特
od = sum_s % (2 ** 32)
return od
def calculate_p(od, n):
"""
生成动态口令
od (int): 一次性中间值,n (int): 动态口令的位数,应不小于6
返回:str: 动态口令(十进制数字字符串)
"""
if n < 6:
raise ValueError("动态口令的位数应不小于6")
# 计算动态口令
password = od % (10 ** n)
# 将数字转换为字符串并返回
return f"{password:0{n}d}"
def main():
# 示例使用
period = 60 # 口令变化周期,单位为秒
input_time=datetime.now()
t = calculate_t(input_time,period)
print(f't={t}')
# Example usage:
T = t#"202310011230" # Example time factor
C = 1357924681 # Example event factor 事件因子
Q = "ABCD1234" # Example challenge factor 挑战因子
id = calculate_id(T=T, C=C, Q=Q)
print(f'id={id.hex()}') # Print in hexadecimal for easy verification
# pattern = re.compile(r"[ 1I0O'、]", flags=re.IGNORECASE)
# Q = pattern.sub('', Q)
# print(Q)
key='2934412A66B7A186DC35DC40E926F9EE'
s=calculate_s(key,id)
print(f's={s}')
od=calculate_od(s)
print(f'od={od}')
n=6
p=calculate_p(od, n)
print(f'p={p}')
T=datetime.now()
N=6
otp=gen_otp(key,T,C,Q,N,Period=60)
print(f'otp={otp}')
if __name__ == '__main__':
main()
python使用sm3实现otp【动态口令】
于 2024-12-21 19:36:05 首次发布
部署运行你感兴趣的模型镜像
您可能感兴趣的与本文相关的镜像
Python3.11
Conda
Python
Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本
3470

被折叠的 条评论
为什么被折叠?



