Skip to content
robby031Public

About

A security-focused, high-performance OTP (TOTP/HOTP) library in Go featuring context binding, anti-phishing, clock skew detection, and replay isolation.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

genotp-go

CI License: MIT

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 26-10-2026

go test ./tests -run=^$ -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/robby031/genotp-go/tests
cpu: Apple M4
BenchmarkHOTPGenerate-10                        10223626               108.9 ns/op             8 B/op          1 allocs/op
BenchmarkHOTPVerify-10                          11288862               106.4 ns/op             0 B/op          0 allocs/op
BenchmarkTOTPGenerate-10                         8580931               139.9 ns/op             8 B/op          1 allocs/op
BenchmarkTOTPGenerateAtFixedTime-10              9957334               107.6 ns/op             8 B/op          1 allocs/op
BenchmarkTOTPVerify-10                           3685792               325.4 ns/op             0 B/op          0 allocs/op
BenchmarkTOTPVerifyWindow0-10                   11423978               106.4 ns/op             0 B/op          0 allocs/op
BenchmarkGenerateSecretDefault-10                6232984               194.0 ns/op            24 B/op          1 allocs/op
BenchmarkGenerateSecret256-10                    6272678               191.2 ns/op            32 B/op          1 allocs/op
BenchmarkBase32Encode-10                        70436312                16.19 ns/op           32 B/op          1 allocs/op
BenchmarkBase32Decode-10                        24082078                50.58 ns/op            0 B/op          0 allocs/op
BenchmarkProvisioningURITOTP-10                  3561573               330.9 ns/op           512 B/op         12 allocs/op
BenchmarkProvisioningURIHOTP-10                  3608091               330.7 ns/op           512 B/op         12 allocs/op
BenchmarkReplayProtectionVerify-10               5823069               206.8 ns/op            76 B/op          1 allocs/op
BenchmarkRateLimiterContention-10                 198138              6156 ns/op             112 B/op          5 allocs/op
BenchmarkConcurrentHOTPVerify-10                   42229             28217 ns/op             208 B/op          5 allocs/op
BenchmarkTOTPVerifyParallel-10                  68901992                16.94 ns/op            0 B/op          0 allocs/op
BenchmarkVerifierParallelFreshCodes-10           2818580               375.9 ns/op            76 B/op          1 allocs/op
PASS
ok      github.com/robby031/genotp-go/tests     23.262s

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.27 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

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

License

MIT — see LICENSE

About

A security-focused, high-performance OTP (TOTP/HOTP) library in Go featuring context binding, anti-phishing, clock skew detection, and replay isolation.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages