动态令牌之 OTP,HOTP,TOTP 的基本原理 Python

2020-12-30 15:48:09 浏览数 (1)

参考链接: Python | 生成一次性密码(OTP)的程序

名词解释和基本介绍: 

OTP 是 One-Time Password的简写,标识一次性密码HOTP 是HMAC-based One-Time Password的简写,表示基于HMAC算法加密的一次性密码。是事件同步,通过某一特定的事件次序及相同的种子值作为输入,通过HASH算法运算出一致的密码。(基于事件)TOTP 是Time-based One-Time Password的简写,表示基于时间戳算法的一次性密码。是时间同步,基于客户端的动态口令和动态口令验证服务器的时间比对,一般每60秒产生一个新口令,要求客户端和服务器能够十分精确的保持正确的时钟,客户端和服务端基于时间计算的动态口令才能一致。 

原理介绍 

OTP基本原理 

计算OTP串的公式:OTP(K,C) = Truncate(HMAC-SHA-1(K,C)) 其中, K表示秘钥串; 

C是一个数字,表示随机数;HMAC-SHA-1表示使用SHA-1做HMAC;Truncate是一个函数,就是怎么截取加密后的串,并取加密后串的哪些字段组成一个数字。 

对HMAC-SHA-1方式加密来说,Truncate实现如下: 

HMAC-SHA-1加密后的长度得到一个20字节的密串;取这个20字节的密串的最后一个字节,取这字节的低4位,作为截取加密串的下标偏移量;按照下标偏移量开始,获取4个字节,按照大端方式组成一个整数;截取这个整数的后6位或者8位转成字符串返回。 

HOTP基本原理 

知道了OTP的基本原理,HOTP只是将其中的参数C变成了随机数HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)) 即:C作为一个参数,获取动态密码。 HOTP的python代码片段: 

class HOTP(OTP):

    def at(self, count):

        """

        Generates the OTP for the given count

        @param [Integer] count counter

        @returns [Integer] OTP

        """

        return self.generate_otp(count)

一般规定HOTP的散列函数使用SHA2,即:基于SHA-256 or SHA-512 [SHA2] 的散列函数做事件同步验证; 

TOTP基本原理 

TOTP只是将其中的参数C变成了由时间戳产生的数字。 TOTP(K,C) = HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)) 不同点是TOTP中的C是时间戳计算得出。 C = (T - T0) / X; 

T 表示当前Unix时间戳T0一般取值为 0.X 表示时间步数,也就是说多长时间产生一个动态密码,这个时间间隔就是时间步数X,系统默认是30秒; 

例如: 

T0 = 0; 

X = 30; 

T = 30 ~ 59, C = 1; 表示30 ~ 59 这30秒内的动态密码一致。 

不同厂家使用的时间步数不同; 

阿里巴巴的身份宝使用的时间步数是60秒;Google的 身份验证器的时间步数是30秒;腾讯的Token时间步数是60秒; 

TOTP的python代码片段: 

class TOTP(OTP):

    def __init__(self, *args, **kwargs):

        """

        @option options [Integer] interval (30) the time interval in seconds

            for OTP This defaults to 30 which is standard.

        """

        self.interval = kwargs.pop('interval', 30)

        super(TOTP, self).__init__(*args, **kwargs)

    def now(self):

        """

        Generate the current time OTP

        @return [Integer] the OTP as an integer

        """

        return self.generate_otp(self.timecode(datetime.datetime.now()))

    def timecode(self, for_time):

        i = time.mktime(for_time.timetuple())

        return int(i / self.interval)

代码说明 

self.interval 是时间步数X 

datetime.datetime.now()为当前的Unix时间戳 

timecode表示(T - T0) / X,即获取获取动态密码计算的随机数。 

TOTP 的实现可以使用HMAC-SHA-256或者HMAC-SHA-512散列函数; 

python的otp实现 

https://pypi.python.org/pypi/pyotp https://github.com/pyotp/pyotp 

基于pyotp的简单应用 

>>> import base64

>>> base64.b32encode('This is my secret key')

'KRUGS4ZANFZSA3LZEBZWKY3SMV2CA23FPE======'

>>> secretKey = base64.b32encode('This is my secret key')

>>> import pyotp

>>> totp = pyotp.TOTP(secretKey)

>>> totp.now()

423779

程序的简单说明 

加载base64的模块,将我的秘钥做一下base32的加密,加载pyotp模块,otp使用base32加密后的秘钥传作为种子,生成随机数字验证的。 

可以使用pyotp和expect一起实现基于google authenticator的自动登录(免去每次双认证,输入密码和动态密码)。 

pyotp的TOTP的使用说明(官网) 

totp = pyotp.TOTP('base32secret3232')

totp.now() # => 492039

# OTP verified for current time

totp.verify(492039) # => True

time.sleep(30)

totp.verify(492039) # => False

pyotp的HOTP的使用说明(官网) 

hotp = pyotp.HOTP('base32secret3232')

hotp.at(0) # => 260182

hotp.at(1) # => 55283

hotp.at(1401) # => 316439

# OTP verified with a counter

hotp.verify(316439, 1401) # => True

hotp.verify(316439, 1402) # => False

使用场景 

服务器登录动态密码验证(如阿里云ECS登录,腾讯机房服务器登录等);公司VPN登录双因素验证;网络接入radius动态密码;银行转账动态密码;网银、网络游戏的实体动态口令牌;等动态密码验证的应用场景。 

市面上基于HOTP的产品 

宁盾令牌阿里巴巴的 身份宝Google的 身份验证器(google-authenticator) 

Google基于TOTP的开源实现 

https://github.com/google/google-authenticator RFC6238中TOTP基于java代码的实现。 

golang的一个otp做的不错的实现 

https://github.com/gitchs/gootp 

RFC参考 

RFC 4226 One-Time Password and HMAC-based One-Time Password.RFC 6238 Time-based One-Time Password.RFC 2104 HMAC Keyed-Hashing for Message Authentication.

0 人点赞