雙重認證(英語:Two-factor authentication,縮寫爲2FA), 又譯爲雙重驗證、雙因子認證、雙因素認證、二元認證,又稱兩步驟驗證(2-Step Verification,又譯兩步驗證), 是一種認證方法,使用兩種不一樣的元素,合併在一塊兒,來確認用戶的身份,是多因素驗證中的一個特例.html
TOTP 的全稱是」基於時間的一次性密碼」(Time-based One-time Password). 它是公認的可靠解決方案,已經寫入國際標準 RFC6238.git
它的步驟以下.github
根據RFC 6238標準,供參考的實現以下:golang
生成一次性密碼的僞代碼算法
function GoogleAuthenticatorCode(string secret) key := base32decode(secret) message := floor(current Unix time / 30) hash := HMAC-SHA1(key, message) offset := last nibble of hash truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset Set the first bit of truncatedHash to zero //remove the most significant bit code := truncatedHash mod 1000000 pad code with 0 until length of code is 6 return code
生成事件性或計數性的一次性密碼僞代碼安全
function GoogleAuthenticatorCode(string secret) key := base32decode(secret) message := counter encoded on 8 bytes hash := HMAC-SHA1(key, message) offset := last nibble of hash truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset Set the first bit of truncatedHash to zero //remove the most significant bit code := truncatedHash mod 1000000 pad code with 0 until length of code is 6 return code
package main import ( "crypto/hmac" "crypto/sha1" "encoding/binary" "fmt" "time" ) func main() { key := []byte("MOJOTV_CN_IS_AWESOME_AND_AWESOME_SECRET_KEY") number := totp(key, time.Now(), 6) fmt.Println("2FA code: ",number) } func hotp(key []byte, counter uint64, digits int) int { //RFC 6238 h := hmac.New(sha1.New, key) binary.Write(h, binary.BigEndian, counter) sum := h.Sum(nil) //取sha1的最後4byte //0x7FFFFFFF 是long int的最大值 //math.MaxUint32 == 2^32-1 //& 0x7FFFFFFF == 2^31 Set the first bit of truncatedHash to zero //remove the most significant bit // len(sum)-1]&0x0F 最後 像登錄 (bytes.len-4) //取sha1 bytes的最後4byte 轉換成 uint32 v := binary.BigEndian.Uint32(sum[sum[len(sum)-1]&0x0F:]) & 0x7FFFFFFF d := uint32(1) //取十進制的餘數 for i := 0; i < digits && i < 8; i++ { d *= 10 } return int(v % d) } func totp(key []byte, t time.Time, digits int) int { return hotp(key, uint64(t.Unix())/30, digits) //return hotp(key, uint64(t.UnixNano())/30e9, digits) }