Documentation ¶
Overview ¶
Package otp generates single use authenticator codes using the HOTP or TOTP algorithms specified in RFC 4226 and RFC 6238 respectively.
See https://tools.ietf.org/html/rfc4226, https://tools.ietf.org/html/rfc6238
Example ¶
package main import ( "crypto/sha256" "fmt" "log" "github.com/creachadair/otp" ) func fixedTime(z uint64) func() uint64 { return func() uint64 { return z } } func main() { cfg := otp.Config{ Hash: sha256.New, // default is sha1.New Digits: 8, // default is 6 // By default, time-based OTP generation uses time.Now. You can plug in // your own function to control how time steps are generated. // This example uses a fixed time step so the output will be consistent. TimeStep: fixedTime(1), } // 2FA setup tools often present the shared secret as a base32 string. // ParseKey decodes this format. if err := cfg.ParseKey("MFYH A3DF EB2G C4TU"); err != nil { log.Fatalf("Parsing key: %v", err) } fmt.Println("HOTP", 0, cfg.HOTP(0)) fmt.Println("HOTP", 1, cfg.HOTP(1)) fmt.Println() fmt.Println("TOTP", cfg.TOTP()) }
Output: HOTP 0 59590364 HOTP 1 86761489 TOTP 86761489
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultHOTP ¶ added in v0.3.1
DefaultHOTP generates an HTOP for the specified counter using the default settings (compatible with Google Authenticator) based on the given key. An error is reported if the key is invalid.
func DefaultTOTP ¶ added in v0.3.1
DefaultTOTP generates a TOTP for the current time step using the default settings (compatible with Google Authenticator) based on the given key. An error is reported if the key is invalid.
func FormatAlphabet ¶ added in v0.2.4
FormatAlphabet constructs a formatting function that truncates the counter hash per RFC 4226 and assigns code digits using the letters of the given alphabet string. Code digits are expanded from most to least significant.
func ParseKey ¶ added in v0.1.1
ParseKey parses a key encoded as base32, the format used by common two-factor authentication setup tools. Whitespace is ignored, case is normalized, and padding is added if required.
func TimeWindow ¶
TimeWindow returns a time step generator that yields the number of n-second intervals elapsed at the current wallclock time since the Unix epoch.
Types ¶
type Config ¶
type Config struct { Key string // shared secret between server and user (required) Hash func() hash.Hash // hash constructor (default is sha1.New) TimeStep func() uint64 // TOTP time step (default is TimeWindow(30)) Counter uint64 // HOTP counter value Digits int // number of OTP digits (default 6) // If set, this function is called with the counter hash to format a code of // the specified length. By default, the code is truncated per RFC 4226 and // formatted as decimal digits (0..9). // // If Format returns a string of the wrong length, code generation panics. Format func(hash []byte, length int) string }
Config holds the settings that control generation of authentication codes. The only required field is Key. The other fields may be omitted, and will use default values compatible with the Google authenticator.
Example (CustomFormat) ¶
package main import ( "fmt" "log" "github.com/creachadair/otp" ) func fixedTime(z uint64) func() uint64 { return func() uint64 { return z } } func main() { // Use settings compatible with Steam Guard: 5 characters and a custom alphabet. cfg := otp.Config{ Digits: 5, Format: otp.FormatAlphabet("23456789BCDFGHJKMNPQRTVWXY"), TimeStep: fixedTime(9876543210), } if err := cfg.ParseKey("CQKQ QEQR AAR7 77X5"); err != nil { log.Fatalf("Parsing key: %v", err) } fmt.Println(cfg.TOTP()) }
Output: FKNK3
Example (RawFormat) ¶
package main import ( "encoding/base64" "fmt" "log" "github.com/creachadair/otp" ) func main() { // The default formatting functions use the RFC 4226 truncation rules, but a // custom formatter may do whatever it likes with the HMAC value. // This example converts to base64. cfg := otp.Config{ Digits: 10, Format: func(hash []byte, nb int) string { return base64.StdEncoding.EncodeToString(hash)[:nb] }, } if err := cfg.ParseKey("MNQWE YTBM5 SAYTS MVQXI"); err != nil { log.Fatalf("Parsing key: %v", err) } fmt.Println(cfg.HOTP(17)) }
Output: j0fLbXLh1Z
func (*Config) Next ¶
Next increments the counter and returns the HOTP corresponding to its new value.