genotp

package module
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 20 Imported by: 0

README

genotp-go

CI Go Report Card codecov Go Reference

Security-focused OTP library in Go. Full implementation of HOTP (RFC 4226) and TOTP (RFC 6238) plus advanced features: context binding, per-context replay isolation, and clock skew detection.

Highlights

  • ✅ Passes all RFC 4226 & RFC 6238 test vectors (SHA1/256/512)
  • ✅ Replay protection + rate limiting with bounded memory
  • ✅ Constant-time comparison to prevent timing attacks
  • Context binding - OTP codes bound to (IP, device, session, origin)
  • Coarse location context - region / geo bucket / distance class helpers
  • Per-context replay isolation - code collisions between users don't block each other
  • Anti-phishing origin binding - origin URL automatically normalized
  • SecretProvider support - additive path for wrapped or externally-resolved secrets
  • HMACProvider support - non-exportable key path for HSM-native OTP
  • Explicit batch verification - additive per-item verify APIs for bulk workloads
  • Clock skew detector with opt-in auto-adjust
  • ✅ Compatible with Google Authenticator / Authy / Microsoft Authenticator (default mode)
  • ✅ Comprehensive test coverage

Installation

go get github.com/robby031/genotp-go

Basic Usage

Standard TOTP (Google Authenticator compatible)
package main

import (
    "fmt"
    "github.com/robby031/genotp-go"
)

func main() {
    secret, _ := genotp.CreateSecret()
    code, _ := genotp.GenTotpDefault(secret)
    valid, _ := genotp.VerifyTotpDefault(secret, code)
    
    fmt.Printf("Code: %s, Valid: %v\n", code, valid)
}
Builder pattern (more ergonomic)
secret, _ := genotp.CreateSecret()

totp, _ := genotp.NewTotpBuilder().
    Secret(secret).
    Algorithm(genotp.SHA1).
    Digits(6).
    Period(30).
    Build()

code, _ := totp.Generate(nil)
valid, _ := totp.Verify(code, nil, 1)
QR code for authenticator app
uri := genotp.NewOtpAuthUri(genotp.TotpType, "ACME:alice@example.com", genotp.EncodeBase32(secret)).
    Issuer("ACME").
    Algorithm(genotp.SHA1).
    Digits(6).
    Period(30).
    Build()

// Render `uri` to QR code (e.g., with a QR code library)
Google Authenticator migration QR (otpauth-migration://)
accounts := []genotp.OtpAuthMigrationAccount{
    {
        Type:      genotp.TotpType,
        Label:     "alice@example.com",
        Issuer:    "Example",
        SecretB32: "JBSWY3DPEHPK3PXP",
        Algorithm: genotp.SHA1,
        Digits:    6,
        Period:    30,
    },
}

uri, err := genotp.BuildOtpAuthMigrationURI(accounts, &genotp.OtpAuthMigrationOptions{
    Version:    1,
    BatchSize:  1,
    BatchIndex: 0,
    BatchID:    123456,
})
if err != nil {
    log.Fatal(err)
}

payload, err := genotp.ParseOtpAuthMigrationURI(uri)
if err != nil {
    log.Fatal(err)
}

fmt.Println(payload.Accounts[0].Label) // alice@example.com

For comprehensive usage examples covering all features — including HOTP/TOTP, builder/config patterns, context binding, verifier, clock skew detection, metrics, and production recommendations — see docs/usage.md.

For external key-manager integrations, see docs/provider_adapters.md for adapter patterns covering wrapped-secret and non-exportable HSM/KMS flows.

SecretProvider-backed OTP
provider := genotp.SecretProviderFunc(func() ([]byte, error) {
    // Example: unwrap from KMS or fetch from a secure external store.
    return wrappedSecretResolver()
})

totp, err := genotp.NewTOTPFromSecretProvider(provider, genotp.SHA1, 6, 30)
if err != nil {
    log.Fatal(err)
}

This mode is additive and keeps the existing API intact. In this v1 design, the provider resolves secret material on demand for each OTP operation, then the temporary buffer is zeroed after use. It improves encrypted-at-rest and external-secret-manager workflows, while leaving room for a future non-exportable HSM-backed HMAC mode.

HMACProvider-backed OTP
provider := genotp.HMACProviderFunc(func(algorithm genotp.Algorithm, message []byte) ([]byte, error) {
    // Example: delegate to an HSM-native or remote HMAC service.
    return hsmSign(algorithm, message)
})

hotp, err := genotp.NewHOTPFromHMACProvider(provider, genotp.SHA256, 6)
if err != nil {
    log.Fatal(err)
}

This path is intended for non-exportable OTP keys. The library sends only the counter/time-step message to the provider and receives the HMAC output back.

Context binding — anti channel OTP intercept (flagship feature)
hotp, _ := genotp.NewHOTP(secret, genotp.SHA1, 6)

// Server binds code to (session + IP hash) of user at issue time:
ctx := genotp.NewOtpContextBuilder().
    Session("login-abc123").
    IP("hash_of_user_ip").
    Build()

code, _ := hotp.GenBound(counter, ctx)
// Send `code` via any channel (SMS, email, WhatsApp, Telegram, push notif, ...).

// When user submits:
if hotp.VerifyBound(form.Code, counter, ctx) {
    // ✓ code correct AND context matches
}
// Attacker who intercepts code from different IP/session -> automatically rejected.

Benchmarks 07-06-2026

go test ./tests -run=^$ -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/robby031/genotp-go/tests
cpu: Apple M4
BenchmarkHOTPGenerate-10                        11958049               100.7 ns/op             8 B/op          1 allocs/op
BenchmarkHOTPVerify-10                          12271438                98.93 ns/op            0 B/op          0 allocs/op
BenchmarkTOTPGenerate-10                         9337573               132.1 ns/op             8 B/op          1 allocs/op
BenchmarkTOTPGenerateAtFixedTime-10             11920894               100.5 ns/op             8 B/op          1 allocs/op
BenchmarkTOTPVerify-10                           4001732               303.8 ns/op             0 B/op          0 allocs/op
BenchmarkTOTPVerifyWindow0-10                   12422841                98.22 ns/op            0 B/op          0 allocs/op
BenchmarkGenerateSecretDefault-10                6406161               185.3 ns/op            24 B/op          1 allocs/op
BenchmarkGenerateSecret256-10                    6735511               179.3 ns/op            32 B/op          1 allocs/op
BenchmarkBase32Encode-10                        61364334                18.57 ns/op           32 B/op          1 allocs/op
BenchmarkBase32Decode-10                        24849778                49.38 ns/op            0 B/op          0 allocs/op
BenchmarkProvisioningURITOTP-10                  3556134               331.0 ns/op           512 B/op         12 allocs/op
BenchmarkProvisioningURIHOTP-10                  3594416               331.2 ns/op           512 B/op         12 allocs/op
BenchmarkReplayProtectionVerify-10               5728464               213.9 ns/op            76 B/op          1 allocs/op
BenchmarkRateLimiterContention-10                 186141              6520 ns/op             112 B/op          5 allocs/op
BenchmarkConcurrentHOTPVerify-10                   43528             27301 ns/op             208 B/op          5 allocs/op
BenchmarkTOTPVerifyParallel-10                  71319079                16.08 ns/op            0 B/op          0 allocs/op
BenchmarkVerifierParallelFreshCodes-10           2907163               377.3 ns/op            76 B/op          1 allocs/op
PASS
ok      github.com/robby031/genotp-go/tests     24.891s

Features

HOTP (RFC 4226)
  • Generate and verify HMAC-based One-Time Passwords
  • Look-ahead resynchronization for counter drift
  • Context binding for enhanced security
TOTP (RFC 6238)
  • Time-based One-Time Passwords with configurable period
  • Window-based verification for clock skew tolerance
  • Support for SHA1, SHA256, and SHA512 algorithms
  • Context binding and clock skew tracking
Context Binding

Bind OTP codes to specific contexts:

  • IP address (or hash thereof)
  • Device identifier
  • Session ID
  • Origin URL (anti-phishing)
  • Region or geo bucket (coarse location context)
  • Distance class (same_area, nearby, far)
  • Custom fields

For production use, prefer coarse, application-defined location labels over raw latitude/longitude. This keeps OTP flows more stable across GPS jitter, platform differences, and privacy constraints.

Two modes:

  1. HMAC binding: Different contexts produce different OTP codes
  2. Verifier-stored: Standard OTP codes, but server validates context
Clock Skew Detection

Track and compensate for clock drift between client and server:

  • Passive mode: only reports statistics
  • Active mode: automatically adjusts verification window
  • Recommends for window sizing or NTP sync
Replay Protection

Prevent OTP code reuse with:

  • Per-context replay isolation
  • Configurable rate limiting
  • Bounded memory usage

API Reference

Core Types
  • Algorithm: SHA1, SHA256, SHA512
  • HOTP: HMAC-based OTP implementation
  • TOTP: Time-based OTP implementation
  • OtpContext: Context binding data
  • ClockSkewDetector: Clock drift tracking
  • Verifier: Replay protection and rate limiting (per-instance)
  • ReplayStore: pluggable backend untuk replay-set (default = in-memory bounded + TTL; untuk multi-replica deployment implement dengan Redis / etcd / sql — lihat docs/distributed_replay_protection.md)
Helper Functions
  • CreateSecret(): Generate a random 160-bit secret
  • GenHotpDefault(): Generate HOTP with default parameters
  • GenTotpDefault(): Generate TOTP with default parameters
  • VerifyHotpDefault(): Verify HOTP with default parameters
  • VerifyTotpDefault(): Verify TOTP with default parameters
  • EncodeBase32(data []byte) string: Encode bytes to Base32 (RFC 4648, no padding)
  • DecodeBase32(dst []byte, src string) (int, error): Decode Base32 ke buffer caller. Strip ASCII whitespace, -, dan = otomatis. Mengembalikan jumlah byte yang ditulis. Returns ErrDstTooSmall jika dst kekecilan, ErrInvalidSecret jika ada karakter invalid.

Testing

# Run all tests
go test ./tests

# Run tests with coverage
go test -v -race -coverprofile=coverage.out ./tests/

# Run fuzz tests (locally)
go test -fuzz=FuzzHOTPGenerate -fuzztime=1m ./fuzz/
go test -fuzz=FuzzTOTPVerify -fuzztime=1m ./fuzz/

All RFC test vectors are included and verified:

  • RFC 4226 HOTP test vectors
  • RFC 6238 TOTP test vectors (SHA1, SHA256, SHA512)
Continuous Integration

The project uses GitHub Actions for automated testing on every push to main and pull requests:

CI Workflow includes:

  • Tests - Run on Go 1.21, 1.22, and 1.23 with race detection
  • Fuzz Tests - 30 seconds per fuzz target (10 fuzz functions total)
  • Linting - golangci-lint with 15+ enabled linters
  • Security Scan - gosec static analysis
  • Build Verification - Ensures code compiles and go.mod is tidy
  • Code Coverage - Uploaded to Codecov

See .github/workflows/ci.yml for the full configuration.

License

MIT — see LICENSE

Documentation

Index

Examples

Constants

View Source
const (
	DistanceClassSameArea = "same_area"
	DistanceClassNearby   = "nearby"
	DistanceClassFar      = "far"
)
View Source
const (
	MinSecretBytes     = 16
	DefaultSecretBytes = 20
)

Variables

View Source
var (
	ErrInvalidSecret      = errors.New("invalid secret key")
	ErrInvalidCode        = errors.New("invalid OTP code")
	ErrInvalidDigits      = errors.New("invalid number of digits")
	ErrInvalidAlgorithm   = errors.New("invalid algorithm")
	ErrInvalidCounter     = errors.New("invalid counter value")
	ErrInvalidTime        = errors.New("invalid time value")
	ErrVerificationFailed = errors.New("OTP verification failed")
	ErrRateLimited        = errors.New("rate limited")
	ErrReplayAttack       = errors.New("replay attack detected")
	ErrDstTooSmall        = errors.New("destination buffer too small")
	ErrSecretProvider     = errors.New("secret provider failure")
	ErrHMACProvider       = errors.New("HMAC provider failure")
	ErrInvalidURI         = errors.New("invalid otpauth URI")
	ErrInvalidMigration   = errors.New("invalid otpauth-migration payload")
)

Functions

func BuildOtpAuthMigrationURI added in v1.2.2

func BuildOtpAuthMigrationURI(
	accounts []OtpAuthMigrationAccount,
	opts *OtpAuthMigrationOptions,
) (string, error)

func CreateSecret

func CreateSecret() ([]byte, error)

func DecodeBase32

func DecodeBase32(dst []byte, src string) (int, error)

func EncodeBase32

func EncodeBase32(data []byte) string

func GenHotpDefault

func GenHotpDefault(secret []byte, counter uint64) (string, error)

func GenTotpDefault

func GenTotpDefault(secret []byte) (string, error)

func VerifyHotpDefault

func VerifyHotpDefault(secret []byte, code string, counter uint64) (bool, error)

func VerifyTotpDefault

func VerifyTotpDefault(secret []byte, code string) (bool, error)

Types

type Algorithm

type Algorithm int
const (
	SHA1 Algorithm = iota
	SHA256
	SHA512
)

func (Algorithm) String

func (a Algorithm) String() string

type ClockSkewDetector

type ClockSkewDetector struct {
	// contains filtered or unexported fields
}

func NewClockSkewDetector

func NewClockSkewDetector(capacity int) *ClockSkewDetector

func (*ClockSkewDetector) CurrentOffset

func (d *ClockSkewDetector) CurrentOffset() int64

func (*ClockSkewDetector) DisableAutoAdjust

func (d *ClockSkewDetector) DisableAutoAdjust()

func (*ClockSkewDetector) EnableAutoAdjust

func (d *ClockSkewDetector) EnableAutoAdjust()

func (*ClockSkewDetector) IsAutoAdjust

func (d *ClockSkewDetector) IsAutoAdjust() bool

func (*ClockSkewDetector) Record

func (d *ClockSkewDetector) Record(matchedOffset int64, windowUsed uint64)

func (*ClockSkewDetector) Report

func (d *ClockSkewDetector) Report() SkewReport

func (*ClockSkewDetector) Reset

func (d *ClockSkewDetector) Reset()

type GenOtpError

type GenOtpError struct {
	Message string
}

func NewGenOtpError

func NewGenOtpError(msg string) *GenOtpError

func (*GenOtpError) Error

func (e *GenOtpError) Error() string

type HMACProvider added in v1.1.2

type HMACProvider interface {
	HMAC(algorithm Algorithm, message []byte) ([]byte, error)
}

HMACProvider computes HMACs without exporting raw secret material to the library process. This is intended for HSM-native, KMS-native, or remote signing flows where the OTP secret must remain non-exportable.

type HMACProviderFunc added in v1.1.2

type HMACProviderFunc func(algorithm Algorithm, message []byte) ([]byte, error)

HMACProviderFunc adapts a function into an HMACProvider.

func (HMACProviderFunc) HMAC added in v1.1.2

func (f HMACProviderFunc) HMAC(algorithm Algorithm, message []byte) ([]byte, error)

type HOTP

type HOTP struct {
	// contains filtered or unexported fields
}

func NewHOTP

func NewHOTP(secret []byte, algorithm Algorithm, digits uint32) (*HOTP, error)

func NewHOTPFromHMACProvider added in v1.1.2

func NewHOTPFromHMACProvider(provider HMACProvider, algorithm Algorithm, digits uint32) (*HOTP, error)
Example
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"fmt"

	"github.com/robby031/genotp-go"
)

func main() {
	secret := []byte("12345678901234567890")

	provider := genotp.HMACProviderFunc(func(algorithm genotp.Algorithm, message []byte) ([]byte, error) {
		// Replace this with a real HSM/KMS MAC call.
		mac := hmac.New(sha256.New, secret)
		mac.Write(message)
		return mac.Sum(nil), nil
	})

	hotp, err := genotp.NewHOTPFromHMACProvider(provider, genotp.SHA256, 6)
	if err != nil {
		fmt.Println("build error:", err)
		return
	}

	code, err := hotp.Generate(12)
	if err != nil {
		fmt.Println("generate error:", err)
		return
	}

	fmt.Println(code)
}
Output:
360470

func NewHOTPFromSecretProvider added in v1.1.2

func NewHOTPFromSecretProvider(provider SecretProvider, algorithm Algorithm, digits uint32) (*HOTP, error)

func NewHotpFromConfig

func NewHotpFromConfig(secret []byte, c HotpConfig) (*HOTP, error)

func (*HOTP) ClearSecret

func (h *HOTP) ClearSecret()

func (*HOTP) GenBound

func (h *HOTP) GenBound(counter uint64, context *OtpContext) (string, error)

func (*HOTP) Generate

func (h *HOTP) Generate(counter uint64) (string, error)

func (*HOTP) Verify

func (h *HOTP) Verify(code string, counter uint64) (bool, error)

func (*HOTP) VerifyBatch added in v1.1.2

func (h *HOTP) VerifyBatch(reqs []HOTPVerifyRequest) []VerifyResult

VerifyBatch verifies a batch of HOTP codes sequentially and returns one result per request. Each item preserves the same semantics as Verify.

func (*HOTP) VerifyBound

func (h *HOTP) VerifyBound(code string, counter uint64, context *OtpContext) (bool, error)

func (*HOTP) VerifyBoundBatch added in v1.1.2

func (h *HOTP) VerifyBoundBatch(reqs []HOTPVerifyBoundRequest) []VerifyResult

VerifyBoundBatch verifies a batch of context-bound HOTP codes sequentially and returns one result per request. Each item preserves the same semantics as VerifyBound.

func (*HOTP) VerifyWithResync

func (h *HOTP) VerifyWithResync(code string, counter uint64, lookAhead uint64) (uint64, bool, error)

type HOTPVerifyBoundRequest added in v1.1.2

type HOTPVerifyBoundRequest struct {
	Code    string
	Counter uint64
	Context *OtpContext
}

type HOTPVerifyRequest added in v1.1.2

type HOTPVerifyRequest struct {
	Code    string
	Counter uint64
}

type HotpBuilder

type HotpBuilder struct {
	// contains filtered or unexported fields
}

func NewHotpBuilder

func NewHotpBuilder() *HotpBuilder

func (*HotpBuilder) Algorithm

func (b *HotpBuilder) Algorithm(algorithm Algorithm) *HotpBuilder

func (*HotpBuilder) Build

func (b *HotpBuilder) Build() (*HOTP, error)

func (*HotpBuilder) Digits

func (b *HotpBuilder) Digits(digits uint32) *HotpBuilder

func (*HotpBuilder) Secret

func (b *HotpBuilder) Secret(secret []byte) *HotpBuilder

type HotpConfig

type HotpConfig struct {
	Algorithm Algorithm
	Digits    uint32
}

func NewHotpConfig

func NewHotpConfig() HotpConfig

func (HotpConfig) WithAlgorithm

func (c HotpConfig) WithAlgorithm(algorithm Algorithm) HotpConfig

func (HotpConfig) WithDigits

func (c HotpConfig) WithDigits(digits uint32) HotpConfig

type InMemoryReplayStore

type InMemoryReplayStore struct {
	// contains filtered or unexported fields
}

func NewInMemoryReplayStore

func NewInMemoryReplayStore(maxSize int) *InMemoryReplayStore

func (*InMemoryReplayStore) CheckAndRecord

func (s *InMemoryReplayStore) CheckAndRecord(key []byte, ttl time.Duration) (bool, error)

func (*InMemoryReplayStore) Reset

func (s *InMemoryReplayStore) Reset() error

func (*InMemoryReplayStore) Size

func (s *InMemoryReplayStore) Size() int

type KeyGen

type KeyGen struct{}

func (*KeyGen) FillSecret

func (k *KeyGen) FillSecret(buf []byte) error

func (*KeyGen) GenerateDefaultSecret

func (k *KeyGen) GenerateDefaultSecret() ([]byte, error)

func (*KeyGen) GenerateSecret

func (k *KeyGen) GenerateSecret(bitLength int) ([]byte, error)

type Metrics

type Metrics struct {
	HotpGenerations   atomic.Uint64
	HotpVerifications atomic.Uint64
	TotpGenerations   atomic.Uint64
	TotpVerifications atomic.Uint64
	Errors            atomic.Uint64
}

func NewMetrics

func NewMetrics() *Metrics

func (*Metrics) GetErrors

func (m *Metrics) GetErrors() uint64

func (*Metrics) GetHotpGenerations

func (m *Metrics) GetHotpGenerations() uint64

func (*Metrics) GetHotpVerifications

func (m *Metrics) GetHotpVerifications() uint64

func (*Metrics) GetTotpGenerations

func (m *Metrics) GetTotpGenerations() uint64

func (*Metrics) GetTotpVerifications

func (m *Metrics) GetTotpVerifications() uint64

func (*Metrics) IncrementError

func (m *Metrics) IncrementError()

func (*Metrics) IncrementHotpGeneration

func (m *Metrics) IncrementHotpGeneration()

func (*Metrics) IncrementHotpVerification

func (m *Metrics) IncrementHotpVerification()

func (*Metrics) IncrementTotpGeneration

func (m *Metrics) IncrementTotpGeneration()

func (*Metrics) IncrementTotpVerification

func (m *Metrics) IncrementTotpVerification()

func (*Metrics) Reset

func (m *Metrics) Reset()

type OtpAuthMigrationAccount added in v1.2.2

type OtpAuthMigrationAccount struct {
	Type      OtpType   `json:"type"`
	Label     string    `json:"label"`
	Issuer    string    `json:"issuer,omitempty"`
	SecretB32 string    `json:"secretB32"`
	Algorithm Algorithm `json:"algorithm"`
	Digits    uint32    `json:"digits"`
	Period    uint64    `json:"period"`
	Counter   uint64    `json:"counter"`
}

type OtpAuthMigrationOptions added in v1.2.2

type OtpAuthMigrationOptions struct {
	Version    int32 `json:"version"`
	BatchSize  int32 `json:"batchSize"`
	BatchIndex int32 `json:"batchIndex"`
	BatchID    int32 `json:"batchId"`
}

type OtpAuthMigrationPayload added in v1.2.2

type OtpAuthMigrationPayload struct {
	Accounts   []OtpAuthMigrationAccount `json:"accounts"`
	Version    int32                     `json:"version"`
	BatchSize  int32                     `json:"batchSize"`
	BatchIndex int32                     `json:"batchIndex"`
	BatchID    int32                     `json:"batchId"`
}

func ParseOtpAuthMigrationURI added in v1.2.2

func ParseOtpAuthMigrationURI(raw string) (*OtpAuthMigrationPayload, error)

type OtpAuthUri

type OtpAuthUri struct {
	// contains filtered or unexported fields
}

func NewOtpAuthUri

func NewOtpAuthUri(typ OtpType, label, secret string) *OtpAuthUri

func (*OtpAuthUri) Algorithm

func (u *OtpAuthUri) Algorithm(algorithm Algorithm) *OtpAuthUri

func (*OtpAuthUri) Build

func (u *OtpAuthUri) Build() string

func (*OtpAuthUri) Counter

func (u *OtpAuthUri) Counter(counter uint64) *OtpAuthUri

func (*OtpAuthUri) Digits

func (u *OtpAuthUri) Digits(digits uint32) *OtpAuthUri

func (*OtpAuthUri) Issuer

func (u *OtpAuthUri) Issuer(issuer string) *OtpAuthUri

func (*OtpAuthUri) Period

func (u *OtpAuthUri) Period(period uint64) *OtpAuthUri

func (*OtpAuthUri) String

func (u *OtpAuthUri) String() string

type OtpContext

type OtpContext struct {
	// contains filtered or unexported fields
}

func NewOtpContext

func NewOtpContext() *OtpContext

func OtpContextFromBytes

func OtpContextFromBytes(b []byte) *OtpContext

func (*OtpContext) Bytes

func (c *OtpContext) Bytes() []byte

func (*OtpContext) IsEmpty

func (c *OtpContext) IsEmpty() bool

type OtpContextBuilder

type OtpContextBuilder struct {
	// contains filtered or unexported fields
}

func NewOtpContextBuilder

func NewOtpContextBuilder() *OtpContextBuilder

func (*OtpContextBuilder) Build

func (b *OtpContextBuilder) Build() *OtpContext

func (*OtpContextBuilder) Custom

func (b *OtpContextBuilder) Custom(key, value string) *OtpContextBuilder

func (*OtpContextBuilder) Device

func (b *OtpContextBuilder) Device(deviceID string) *OtpContextBuilder

func (*OtpContextBuilder) DistanceClass added in v1.1.2

func (b *OtpContextBuilder) DistanceClass(class string) *OtpContextBuilder

DistanceClass binds the OTP to a coarse proximity class. Invalid values are ignored to preserve builder ergonomics and compatibility.

func (*OtpContextBuilder) GeoBucket added in v1.1.2

func (b *OtpContextBuilder) GeoBucket(bucket string) *OtpContextBuilder

GeoBucket binds the OTP to a coarse location bucket generated by the application, such as a grid cell or geohash prefix chosen by the caller.

func (*OtpContextBuilder) IP

func (*OtpContextBuilder) Origin

func (b *OtpContextBuilder) Origin(origin string) *OtpContextBuilder

func (*OtpContextBuilder) Region added in v1.1.2

func (b *OtpContextBuilder) Region(region string) *OtpContextBuilder

Region binds the OTP to a coarse, application-defined area label such as "id-lmg-bluluk" or "us-nyc-midtown". This is intentionally more stable than raw latitude/longitude for production OTP flows.

func (*OtpContextBuilder) Session

func (b *OtpContextBuilder) Session(session string) *OtpContextBuilder

type OtpType

type OtpType int
const (
	HotpType OtpType = iota
	TotpType
)

type ReplayStore

type ReplayStore interface {
	CheckAndRecord(key []byte, ttl time.Duration) (firstSeen bool, err error)
	Reset() error
}

type SecretProvider added in v1.1.2

type SecretProvider interface {
	Secret() ([]byte, error)
}

SecretProvider resolves secret material on demand for provider-backed HOTP and TOTP instances. Implementations may fetch from wrapped storage, a KMS unwrap flow, or other external secret managers.

type SecretProviderFunc added in v1.1.2

type SecretProviderFunc func() ([]byte, error)

SecretProviderFunc adapts a function into a SecretProvider.

func (SecretProviderFunc) Secret added in v1.1.2

func (f SecretProviderFunc) Secret() ([]byte, error)

type SkewRecommend

type SkewRecommend int
const (
	InsufficientData SkewRecommend = iota
	NoActionNeeded
	ConsistentDrift
	WidenWindowOrCheckNtp
)

func (SkewRecommend) String

func (r SkewRecommend) String() string

type SkewReport

type SkewReport struct {
	SampleCount  int
	MeanOffset   float64
	NonZeroCount int
	EdgeHitRatio float64
	Recommend    SkewRecommend
}

type TOTP

type TOTP struct {
	// contains filtered or unexported fields
}

func NewTOTP

func NewTOTP(secret []byte, algorithm Algorithm, digits uint32, period uint64) (*TOTP, error)

func NewTOTPFromHMACProvider added in v1.1.2

func NewTOTPFromHMACProvider(provider HMACProvider, algorithm Algorithm, digits uint32, period uint64) (*TOTP, error)

func NewTOTPFromSecretProvider added in v1.1.2

func NewTOTPFromSecretProvider(provider SecretProvider, algorithm Algorithm, digits uint32, period uint64) (*TOTP, error)
Example
package main

import (
	"fmt"

	"github.com/robby031/genotp-go"
)

func main() {
	encryptedSecret := []byte("wrapped-user-secret")

	provider := genotp.SecretProviderFunc(func() ([]byte, error) {
		// Replace this with a real KMS decrypt or secret manager fetch.
		_ = encryptedSecret
		return []byte("12345678901234567890"), nil
	})

	totp, err := genotp.NewTOTPFromSecretProvider(provider, genotp.SHA1, 6, 30)
	if err != nil {
		fmt.Println("build error:", err)
		return
	}

	timeVal := uint64(1234567890)
	code, err := totp.Generate(&timeVal)
	if err != nil {
		fmt.Println("generate error:", err)
		return
	}

	fmt.Println(code)
}
Output:
005924

func NewTotpFromConfig

func NewTotpFromConfig(secret []byte, c TotpConfig) (*TOTP, error)

func (*TOTP) ClearSecret

func (t *TOTP) ClearSecret()

func (*TOTP) GenBound

func (t *TOTP) GenBound(context *OtpContext, timeVal *uint64) (string, error)

func (*TOTP) Generate

func (t *TOTP) Generate(timeVal *uint64) (string, error)

func (*TOTP) Verify

func (t *TOTP) Verify(code string, timeVal *uint64, window uint64) (bool, error)

func (*TOTP) VerifyBatch added in v1.1.2

func (t *TOTP) VerifyBatch(reqs []TOTPVerifyRequest) []VerifyResult

VerifyBatch verifies a batch of TOTP codes sequentially and returns one result per request. Each item preserves the same semantics as Verify.

func (*TOTP) VerifyBound

func (t *TOTP) VerifyBound(code string, context *OtpContext, timeVal *uint64, window uint64) (bool, error)

func (*TOTP) VerifyBoundBatch added in v1.1.2

func (t *TOTP) VerifyBoundBatch(reqs []TOTPVerifyBoundRequest) []VerifyResult

VerifyBoundBatch verifies a batch of context-bound TOTP codes sequentially and returns one result per request. Each item preserves the same semantics as VerifyBound.

func (*TOTP) VerifyTracking

func (t *TOTP) VerifyTracking(code string, timeVal *uint64, window uint64, detector *ClockSkewDetector) (bool, error)

type TOTPVerifyBoundRequest added in v1.1.2

type TOTPVerifyBoundRequest struct {
	Code    string
	Context *OtpContext
	Time    *uint64
	Window  uint64
}

type TOTPVerifyRequest added in v1.1.2

type TOTPVerifyRequest struct {
	Code   string
	Time   *uint64
	Window uint64
}

type TotpBuilder

type TotpBuilder struct {
	// contains filtered or unexported fields
}

func NewTotpBuilder

func NewTotpBuilder() *TotpBuilder

func (*TotpBuilder) Algorithm

func (b *TotpBuilder) Algorithm(algorithm Algorithm) *TotpBuilder

func (*TotpBuilder) Build

func (b *TotpBuilder) Build() (*TOTP, error)

func (*TotpBuilder) Digits

func (b *TotpBuilder) Digits(digits uint32) *TotpBuilder

func (*TotpBuilder) Period

func (b *TotpBuilder) Period(period uint64) *TotpBuilder

func (*TotpBuilder) Secret

func (b *TotpBuilder) Secret(secret []byte) *TotpBuilder

type TotpConfig

type TotpConfig struct {
	Algorithm Algorithm
	Digits    uint32
	Period    uint64
}

func NewTotpConfig

func NewTotpConfig() TotpConfig

func (TotpConfig) WithAlgorithm

func (c TotpConfig) WithAlgorithm(algorithm Algorithm) TotpConfig

func (TotpConfig) WithDigits

func (c TotpConfig) WithDigits(digits uint32) TotpConfig

func (TotpConfig) WithPeriod

func (c TotpConfig) WithPeriod(period uint64) TotpConfig

type Verifier

type Verifier struct {
	// contains filtered or unexported fields
}

func NewVerifier

func NewVerifier(maxAttempts uint32) *Verifier

func NewVerifierWithCapacity

func NewVerifierWithCapacity(maxAttempts uint32, maxUsedCodes int) *Verifier

func NewVerifierWithStore

func NewVerifierWithStore(maxAttempts uint32, store ReplayStore, ttl time.Duration) *Verifier

func (*Verifier) ClearUsedCodes

func (v *Verifier) ClearUsedCodes()

func (*Verifier) IsRateLimited

func (v *Verifier) IsRateLimited() bool

func (*Verifier) ResetAttempts

func (v *Verifier) ResetAttempts()

func (*Verifier) VerifyWithContext

func (v *Verifier) VerifyWithContext(code, expected string, issuedContext, requestContext *OtpContext) bool

func (*Verifier) VerifyWithReplayProtection

func (v *Verifier) VerifyWithReplayProtection(code, expected string) bool

type VerifyResult added in v1.1.2

type VerifyResult struct {
	OK  bool
	Err error
}

VerifyResult holds the outcome of a single batch verification item.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL