動態令牌-(OTP,HOTP,TOTP)-基本原理


動態令牌-(OTP,HOTP,TOTP)-基本原理

摘自 https://www.cnblogs.com/voipman/p/6216328.html

 

名詞解釋和基本介紹

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):
         =  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基於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.

 

Done.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM