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/wryhuman/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 ¶
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 ¶
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 ¶
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 ¶
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 is the shared secret used to generate OTP codes.
// This field must be set for codes to be generated.
// The value must not be encoded in base32 or similar.
Key string
// Hash, if non-nil, is used to construct the hash for OTP generation.
// If nil, the default is sha1.New.
Hash func() hash.Hash
// TimeStep, if non-nil, returns the current time window to use for TOTP
// generation each time it is called. If nil, TimeWindow(30) is used.
TimeStep func() uint64
// Counter is the current HOTP counter value. It is incremented each time
// the Next method is called.
Counter uint64
// Digits indicates the number of digits a generated code will have.
// If zero or negative, the default is 6.
Digits int
// Format, if set, is called with the counter hash to format a code of the
// specified length. By default, the code is truncated per RFC 4226 (see
// Truncate) 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/wryhuman/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/wryhuman/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.