Golang 入门资料+笔记Golang深入浅出golang

Golang 2FA双因素认证

2020-01-14  本文已影响0人  MojoTech
image.png

原文 https://mojotv.cn/go/golang-2fa

1. 前言

双重认证(英语:Two-factor authentication,缩写为2FA), 又译为双重验证、双因子认证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证), 是一种认证方法,使用两种不同的元素,合并在一起,来确认用户的身份,是多因素验证中的一个特例.

2. TOTP的概念

TOTP 的全称是”基于时间的一次性密码”(Time-based One-time Password). 它是公认的可靠解决方案,已经写入国际标准 RFC6238.

它的步骤如下.

3. RFC6238

根据RFC 6238标准,供参考的实现如下:

4. 2FA双因素认证 Golang 代码实现 TOTP

生成一次性密码的伪代码

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)
}

5. 参考

上一篇下一篇

猜你喜欢

热点阅读