package main import ( "crypto/rand" "crypto/hmac" "crypto/sha1" "encoding/base32" "time" "fmt" ) func encodeHMACSHA1(data []byte, secret []byte) []byte { h := hmac.New(sha1.New, []byte(secret)) h.Write(data) sha := h.Sum(nil) return sha } func secret() string { secretKey := make([]byte, 5) rand.Read(secretKey) return base32.StdEncoding.EncodeToString(secretKey) } func makeTimestamp() int64 { return time.Now().UnixNano() / int64(time.Millisecond) } func generate(secretKey string) (string, error) { key, err := base32.StdEncoding.DecodeString(secretKey) if err != nil { return "", err } l := makeTimestamp() / (1000 * 30) return getHash(key, l), nil } func getHash(secretKey []byte, l int64) (string) { data := make([]byte, 8) for i := 7; i >= 0; i-- { data[i] = byte(l) l = l >> 8 } hash := encodeHMACSHA1(data, secretKey) offset := int(hash[20 - 1] & 0xF) truncatedHash := 0 for i := 0; i < 4; i++ { truncatedHash <<= 8 truncatedHash |= int(hash[offset + i] & 0xFF) } truncatedHash &= 0x7FFFFFFF truncatedHash %= 1000000 return fmt.Sprintf("%06d", truncatedHash) } func main() { secretKey := secret() println(secretKey) otp, _ := generate(secretKey) println(otp) }