动态令牌-(OTP,HOTP,TOTP)-基本原理

it2022-05-05  106

名词解释和基本介绍

OTP 是 One-Time Password的简写,表示一次性密码。

HOTP 是HMAC-based One-Time Password的简写,表示基于HMAC算法加密的一次性密码。

  是事件同步,通过某一特定的事件次序及相同的种子值作为输入,通过HASH算法运算出一致的密码。

TOTP 是Time-based One-Time Password的简写,表示基于时间戳算法的一次性密码。 

  是时间同步,基于客户端的动态口令和动态口令验证服务器的时间比对,一般每60秒产生一个新口令,要求客户端和服务器能够十分精确的保持正确的时钟,客户端和服务端基于时间计算的动态口令才能一致。  

原理介绍

OTP基本原理

计算OTP串的公式

1 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位转成字符串返回。

 Java代码实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public static String generateOTP(String K,                                       String C,                                       String returnDigits,                                       String crypto){         int codeDigits = Integer.decode(returnDigits).intValue();         String result = null ;           // K是密码         // C是产生的随机数         // crypto是加密算法 HMAC-SHA-1         byte [] hash = hmac_sha(crypto, K, C);         // hash为20字节的字符串           // put selected bytes into result int         // 获取hash最后一个字节的低4位,作为选择结果的开始下标偏移         int offset = hash[hash.length - 1 ] & 0xf ;           // 获取4个字节组成一个整数,其中第一个字节最高位为符号位,不获取,使用0x7f         int binary =                 ((hash[offset] & 0x7f ) << 24 ) |                 ((hash[offset + 1 ] & 0xff ) << 16 ) |                 ((hash[offset + 2 ] & 0xff ) << 8 ) |                 (hash[offset + 3 ] & 0xff );         // 获取这个整数的后6位(可以根据需要取后8位)         int otp = binary % 1000000 ;         // 将数字转成字符串,不够6位前面补0         result = Integer.toString(otp);         while (result.length() < codeDigits) {             result = "0" + result;         }         return result;     }

返回的结果就是看到一个数字的动态密码。

 

HOTP基本原理

知道了OTP的基本原理,HOTP只是将其中的参数C变成了随机数

公式修改一下

1 HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

HOTP: Generates the OTP for the given count

即:C作为一个参数,获取动态密码。

HOTP的python代码片段:

1 2 3 4 5 6 7 8 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变成了由时间戳产生的数字。

1 TOTP(K,C) = HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

不同点是TOTP中的C是时间戳计算得出。

1 C = (T - T0) / X;

T 表示当前Unix时间戳

T0一般取值为 0.

X 表示时间步数,也就是说多长时间产生一个动态密码,这个时间间隔就是时间步数X,系统默认是30秒;

例如:

T0 = 0;

X = 30;

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

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

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

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

TOTP的python代码片段:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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的简单应用

1 2 3 4 5 6 7 8 >>> 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的使用说明(官网)

1 2 3 4 5 6 7 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的使用说明(官网) 

1 2 3 4 5 6 7 8 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.

转载于:https://www.cnblogs.com/Horne/p/6945831.html

相关资源:nd-otp-webcrypto:简单的TOTP代码生成器-源码

最新回复(0)