1、OTP、HOTP、TOTP 簡介
1.1、OTP
One-Time Password 簡寫,表示一次性密碼。
1.2、HOTP
HMAC-based One-Time Password 簡寫,表示基于 HMAC 算法加密的一次性密碼。是事件同步,通過某一特定的事件次序及相同的種子值作為輸入,通過 HASH 算法運算出一緻的密碼。
1.3、TOTP
Time-based One-Time Password 簡寫,表示基于時間戳算法的一次性密碼。
時間同步,基于用戶端的動态密碼和動态密碼驗證伺服器的時間比對,一般每 60 秒産生一個新密碼,要求用戶端和伺服器能夠十分精确的保持正确的時鐘,用戶端和服務端基于時間計算的動态密碼才能一緻。
2、TOTP 弱點和漏洞編輯
TOTP 代碼可以像密碼一樣被釣魚,但它們需要網絡釣魚者實時代理憑證,而不是及時收集它們,不限制登入嘗試的實作容易受到強制執行代碼的攻擊。
竊取共享密鑰的攻擊者可以随意生成新的有效 TOTP 代碼。如果攻擊者破壞了大型身份驗證資料庫,這可能是一個特殊問題。
由于 TOTP 裝置的電池電量不足,時鐘可以解除同步,并且由于軟體版本在使用者可能丢失或被盜的手機上,是以所有實際實施都有繞過保護的方法(例如:列印的代碼,電子郵件 - 重置等),這可能給大型使用者群帶來相當大的支援負擔,并且還為欺詐使用者提供額外的利用向量。
TOTP 代碼的有效期超過它們在螢幕上顯示的時間(通常是兩倍或更多倍)。這是一個讓步,認證和認證方的時鐘可以大幅度扭曲。
所有一次性基于密碼的身份驗證方案(包括 TOTP 和 HOTP 等)仍然容易受到會話劫持,即在使用者登入後占用使用者的會話。
3、原理介紹
3.1、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 位轉成字元串傳回。
示例:
Java 代碼實作:
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;
}
傳回的結果就是看到一個數字的動态密碼。
3.2、HOTP 基本原理
知道了 OTP 的基本原理,HOTP 隻是将其中的參數 C 變成了随機數。
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
HOTP:
Generates the OTP for the given count
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] 的散列函數做事件同步驗證;
3.3、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,也就是 1970 年 1 月 1 日。
是以上式可以簡化為:
C = T / X;
X 表示時間步數,也就是說多長時間産生一個動态密碼,這個時間間隔就是時間步數 X,系統預設是 30 秒;
例如:
T0 = 0;
X = 30;
簡化為:C = T / 30
1)T = 30 ~ 59
C = 1;
表示 30 ~ 59 這 30 秒内的動态密碼一緻。
2)T = 60 ~ 89
C = 2;
表示 30 ~ 59 這 30 秒内的動态密碼一緻。
不同廠家使用的時間步數不同:
阿裡巴巴的身份寶使用的時間步數是 60 秒;
甯盾令牌使用的時間步數是 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 散列函數;
TOTP 的要求:
用戶端和伺服器必須能夠彼此知道或者推算出對方的 Unix Time;
用戶端和伺服器端必須共享一個密鑰;
算法必須使用 HOTP 作為其關鍵實作環節;
用戶端和伺服器端必須使用相同的步長 X;
每一個用戶端必須擁有不同的密鑰;
密鑰的生成必須足夠随機;
密鑰必須儲存在防篡改的裝置上,而且不能在不安全的情況下被通路或使用;
對該算法中 T 的實作必須大于 int32,因為它在 2038 年将超出上限;
T0 和 X 的協商必須在之前的步驟中就已經做好了。
4、參考
4.1、python 的 otp 實作
https://pypi.python.org/pypi/pyotp
https://github.com/pyotp/pyotp
4.2、基于 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的自動登入(免去每次雙認證,輸入密碼和動态密碼)。
4.3、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
4.4、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
4.5、使用場景
伺服器登入動态密碼驗證(如阿裡雲ECS登入,騰訊機房伺服器登入等);
公司VPN登入雙因素驗證;
網絡接入radius動态密碼;
銀行轉賬動态密碼;
網銀、網絡遊戲的實體動态密碼牌;
等動态密碼驗證的應用場景。
4.6、市面上基于 HOTP 的産品
甯盾令牌
阿裡巴巴的身份寶
Google 的身份驗證器(google-authenticator)
4.7、Google 基于 TOTP 的開源實作
https://github.com/google/google-authenticator
RFC6238中TOTP基于java代碼的實作。
4.8、golang 的一個 otp 實作
https://github.com/gitchs/gootp
4.9、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.
refer:
https://www.cnblogs.com/voipman/p/6216328.html
http://www.bubuko.com/infodetail-1884978.html