Go实现Google Authenticator
## 获取密钥 下面提供了一个将字符串转为16位大写字符串的函数,返回结果可作为Google验证器的密钥。 ```go func StrTo16Upper(s string) string { var alphabet = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ") hash := md5.Sum([]byte(s)) var result string for i := 0; i < 16; i++ { index := int(hash[i]) % len(alphabet) result += string(alphabet[index]) } return result } ``` ## 验证函数 传入密钥和验证码,通过`getCode`函数获取Google验证码,判断输入的验证码与Google验证码是否相同。 为减小误差,对前后30s的Google验证码都进行验证。 ```go func VerifyCode(secret string, code int32) bool { // 当前google验证码 if getCode(secret, 0) == code { return true } // 前30秒google验证码 if getCode(secret, -30) == code { return true } // 后30秒google验证码 if getCode(secret, 30) == code { return true } return false } ``` ## 获取验证码 通过密钥和时间的偏移量获取Google验证码。 ```go func getCode(secret string, offset int64) int32 { key, err := base32.StdEncoding.DecodeString(secret) if err != nil { fmt.Println(err) return 0 } epochSeconds := time.Now().Unix() + offset return int32(oneTimePassword(key, toBytes(epochSeconds/30))) } ``` ## 其它函数 ### toBytes 把一个int64数字转换成字节数组。它通过位运算把数字拆分成8个字节并按大端序存储。 ```go func toBytes(value int64) []byte { var result []byte mask := int64(0xFF) shifts := [8]uint16{56, 48, 40, 32, 24, 16, 8, 0} for _, shift := range shifts { result = append(result, byte((value>>shift)&mask)) } return result } ``` ### toUint32 把一个4字节的字节数组转换成一个uint32数字。它使用位运算来组合字节。 ```go func toUint32(bytes []byte) uint32 { return (uint32(bytes[0]) << 24) + (uint32(bytes[1]) << 16) + (uint32(bytes[2]) << 8) + uint32(bytes[3]) } ``` ### oneTimePassword 生成器的核心。它的参数包含一个密钥key和一个要进行HMAC运算的值value。 1. 它首先使用key初始化一个HMAC-SHA1算法的计算实例。 2. 然后对value进行HMAC哈希计算,结果存储在hash中。 3. 它取哈希值的最后一个字节的低4位作为偏移量offset。 4. 使用偏移量取哈希值的4个字节作为密码的源数据hashParts。 5. 对第一个字节去除高位后转成一个uint32数字。 6. 最后对1,000,000求余生成6位数的OTP。 ```go func oneTimePassword(key []byte, value []byte) uint32 { hmacSha1 := hmac.New(sha1.New, key) hmacSha1.Write(value) hash := hmacSha1.Sum(nil) offset := hash[len(hash)-1] & 0x0F hashParts := hash[offset : offset+4] hashParts[0] = hashParts[0] & 0x7F number := toUint32(hashParts) pwd := number % 1000000 return pwd } ```
创建时间:2023-12-28
|
最后修改:2023-12-29
|
©允许规范转载
酷酷番茄
首页
文章
友链