TOTP是什么?
TOTP 是Time-based One-Time Password的簡寫,表示基于時間戳算法的一次性密碼。
是時間同步,基于客戶端的動態(tài)口令和動態(tài)口令驗證服務(wù)器的時間比對,一般每60秒,或30秒產(chǎn)生一個新口令,要求客戶端和服務(wù)器能夠十分精確的保持正確的時鐘,客戶端和服務(wù)端基于時間計算的動態(tài)口令才能一致。
適用場景
- 服務(wù)器登錄動態(tài)密碼驗證
- 公司VPN登錄雙因素驗證
- 銀行轉(zhuǎn)賬動態(tài)密碼
- 網(wǎng)銀、網(wǎng)絡(luò)游戲的實體動態(tài)口令牌
- 等基于時間有效性驗證的應(yīng)用場景
TOTP的基本原理
TOTP計算公式
TOTP(K, TC) = Truncate(HMAC-SHA-1(K, TC))
K,密鑰串
HMAC-SHA-1, 表示使用SHA-1做HMAC(當(dāng)然也可以使用SHA-256等)
C,基于時間戳計算得出,通過定義紀(jì)元(T0)的開始并以時間間隔(TI)為單位計數(shù),將當(dāng)前時間戳變?yōu)檎麛?shù)時間計數(shù)器(TC)
Truncate,是一個函數(shù),用于截取加密后的字符串
TC的計算公式
TC = (T - T0) / T1;
T,當(dāng)前的時間戳
T0,起始時間,一般為0
T1,時間間隔,根據(jù)業(yè)務(wù)需要自定義
Truncate函數(shù)
- 取加密后的最后一個字節(jié)的的低4位,offset;
- 以offset開始取4個字節(jié),按照大端方式組成整數(shù),binary;
- 根據(jù)需要的長度對binary取模,opt
- 以字符串方式返回opt,并補足長度
h = hmac.new(self.key.encode(), msg, sha256).digest()
offset = h[len(h)-1] & 0xf
binary = (h[offset] & 0x7f) << 24
binary = binary | ((h[offset+1] & 0xff)<<16)
binary = binary | ((h[offset+2] & 0xff)<<8)
binary = binary | (h[offset+3] & 0xff)
otp = binary % (10 ** self.codeDigits)
return str(otp).rjust(self.codeDigits, '0')
Python實現(xiàn)
import binascii
import hmac
import time
from hashlib import sha256
class TOTP:
def __init__(self, key, codeDigits):
self.key = key
self.codeDigits = codeDigits
def truncate(self, time):
time = time.rjust(16,'0')
bigint = binascii.unhexlify(hex(int('10'+time, 16))[2:])
msg = bigint[1:len(bigint)]
h = hmac.new(self.key, msg, sha256).digest()
offset = h[len(h)-1] & 0xf
binary = (h[offset] & 0x7f) << 24
binary = binary | ((h[offset+1] & 0xff)<<16)
binary = binary | ((h[offset+2] & 0xff)<<8)
binary = binary | (h[offset+3] & 0xff)
otp = binary % (10 ** self.codeDigits)
return str(otp).rjust(self.codeDigits, '0')
def tc(self, ttl):
return format(int(int(time.time())/int(ttl)),'x').upper()
上面的代碼就是我基于python3的實現(xiàn)(可以保存為totp.py),散列算法使用的是SHA-256,使用方式如下:
import totp
import base64
secretKey = base64.b32encode(b'My secret key')
t = totp.TOTP(secretKey, 4)
time = t.tc(60) # 此處時間單位為秒
result=t.truncate(time)
print(result)
源碼可以從這里獲?。?br> github