func generateOTP(base32Key string, counter int64, digits int, algo string) (string, error) {
	counterBytes := make([]byte, 8)
	binary.BigEndian.PutUint64(counterBytes, uint64(counter)) // convert counter to byte array
	rawBase32Key := strings.TrimRight(base32Key, "=")         // remove padding and use RawEncoding
	secretKey, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(rawBase32Key)
	if err != nil {
		return "", errors.New("bad OTP secret key: " + err.Error())
	}

	var hasher hash.Hash
	switch strings.ToUpper(algo) {
	case "SHA1":
		hasher = hmac.New(sha1.New, secretKey)
	case "SHA256":
		hasher = hmac.New(sha256.New, secretKey)
	case "SHA512":
		hasher = hmac.New(sha512.New, secretKey)
	// although once part of Google Key Uri Format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format/_history
	// removed MD5 as unreliable - only digests of length >= 20 can be used (MD5 has a digest length of 16)
	// case AlgorithmMD5:
	// 	hasher = md5.New()
	default:
		return "", errors.New("invalid OTP algorithm. Please use any one of SHA1/SHA256/SHA512")
	}

	if _, err = hasher.Write(counterBytes); err != nil {
		return "", errors.New("unable to compute HMAC: " + err.Error())
	}

	hash := hasher.Sum(nil)

	// truncate hash
	offset := hash[len(hash)-1] & 0x0F
	hash = hash[offset : offset+4]
	hash[0] = hash[0] & 0x7F

	decimal := binary.BigEndian.Uint32(hash)
	otp := decimal % uint32(math.Pow10(digits))

	result := strconv.Itoa(int(otp))
	if len(result) < digits {
		padded := strings.Repeat("0", digits) + result
		result = padded[len(padded)-digits:]
	}

	return result, nil
}
// Generates TOTP/HOTP code.
Generates TOTP/HOTP code.
// Generates TOTP / HOTP code .
func generateOTP(base32Key string, counter int64, digits int, algo string) (string, error) {
	counterBytes := make([]byte, 8)
	binary.BigEndian.PutUint64(counterBytes, uint64(counter)) 
	rawBase32Key := strings.TrimRight(base32Key, "=")         
	secretKey, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(rawBase32Key)
	if err != nil {
		return "", errors.New("bad OTP secret key: " + err.Error())
	}
	var hasher hash.Hash
	switch strings.ToUpper(algo) {
	case "SHA1":
		hasher = hmac.New(sha1.New, secretKey)
	case "SHA256":
		hasher = hmac.New(sha256.New, secretKey)
	case "SHA512":
		hasher = hmac.New(sha512.New, secretKey)
	default:
		return "", errors.New("invalid OTP algorithm. Please use any one of SHA1/SHA256/SHA512")
	}
	if _, err = hasher.Write(counterBytes); err != nil {
		return "", errors.New("unable to compute HMAC: " + err.Error())
	}
	hash := hasher.Sum(nil)
	offset := hash[len(hash)-1] & 0x0F
	hash = hash[offset : offset+4]
	hash[0] = hash[0] & 0x7F
	decimal := binary.BigEndian.Uint32(hash)
	otp := decimal % uint32(math.Pow10(digits))
	result := strconv.Itoa(int(otp))
	if len(result) < digits {
		padded := strings.Repeat("0", digits) + result
		result = padded[len(padded)-digits:]
	}
	return result, nil
}
func generateOTP ( base32Key string , counter int64 , digits int , algo string ) ( string , error ) { counterBytes := make ( [ ] byte , 8 ) binary . BigEndian . PutUint64 ( counterBytes , uint64 ( counter ) ) rawBase32Key := strings . TrimRight ( base32Key , " " ) secretKey , err := base32 . StdEncoding . WithPadding ( base32 . NoPadding ) . DecodeString ( rawBase32Key ) if err != nil { return " " , errors . New ( " " + err . Error ( ) ) } var hasher hash . Hash switch strings . ToUpper ( algo ) { case " " : hasher = hmac . New ( sha1 . New , secretKey ) case " " : hasher = hmac . New ( sha256 . New , secretKey ) case " " : hasher = hmac . New ( sha512 . New , secretKey ) default : return " " , errors . New ( " " ) } if _ , err = hasher . Write ( counterBytes ) ; err != nil { return " " , errors . New ( " " + err . Error ( ) ) } hash := hasher . Sum ( nil ) offset := hash [ len ( hash ) - 1 ] & 0x0F hash = hash [ offset : offset + 4 ] hash [ 0 ] = hash [ 0 ] & 0x7F decimal := binary . BigEndian . Uint32 ( hash ) otp := decimal % uint32 ( math . Pow10 ( digits ) ) result := strconv . Itoa ( int ( otp ) ) if len ( result ) < digits { padded := strings . Repeat ( " " , digits ) + result result = padded [ len ( padded ) - digits : ] } return result , nil }
Generates TOTP/HOTP code.
Generates TOTP / HOTP code .
// convert counter to byte array // remove padding and use RawEncoding // although once part of Google Key Uri Format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format/_history // removed MD5 as unreliable - only digests of length >= 20 can be used (MD5 has a digest length of 16) // case AlgorithmMD5: // 	hasher = md5.New() // truncate hash