go-totp
is a simple Go package to implement Timebased-One-Time-Password authentication functionality, a.k.a. TOTP
, to the Go app.
- Compatible Authenticator apps | Wiki @ GitHub
Note: This is a wrapper of the awesome
github.com/pquerna/otp
package to facilitate the use of TOTP.As an optional feature, this package supports ECDH (Elliptic-Curve Diffie-Hellman) key agreement protocol, where public keys are exchanged between two parties to obtain a common TOTP passcode.
// Install module
go get "github.com/KEINOS/go-totp"
// Use package
import "github.com/KEINOS/go-totp/totp"
// import "github.com/KEINOS/go-totp/totp"
func Example() {
Issuer := "Example.com" // name of the service
AccountName := "[email protected]" // name of the user
// Generate a new secret key with default options.
// Compatible with most TOTP authenticator apps.
key, err := totp.GenerateKey(Issuer, AccountName)
if err != nil {
log.Fatal(err)
}
// Print the default option values.
fmt.Println("- Algorithm:", key.Options.Algorithm)
fmt.Println("- Period:", key.Options.Period)
fmt.Println("- Secret Size:", key.Options.SecretSize)
fmt.Println("- Skew (time tolerance):", key.Options.Skew)
fmt.Println("- Digits:", key.Options.Digits)
// Generate 6 digits passcode (valid for 30 seconds)
passcode, err := key.PassCode()
if err != nil {
log.Fatal(err)
}
// Validate the passcode
if key.Validate(passcode) {
fmt.Println("* Validation result: Passcode is valid")
}
//
// Output:
// - Algorithm: SHA1
// - Period: 30
// - Secret Size: 128
// - Skew (time tolerance): 1
// - Digits: 6
// * Validation result: Passcode is valid
}
- View it online @ Go Playground
// ----------------------------------------------------------------------------
// Generate a new secret key with custom options
// ----------------------------------------------------------------------------
key, err := totp.GenerateKey(Issuer, AccountName,
totp.WithAlgorithm(totp.Algorithm("SHA256")),
totp.WithPeriod(15),
totp.WithSecretSize(256),
totp.WithSkew(5),
totp.WithDigits(totp.DigitsEight),
)
// ----------------------------------------------------------------------------
// Major methods of totp.Key object
// ----------------------------------------------------------------------------
// * You should handle the error in your code.
// Generate the current passcode.
//
// Which is a string of 8 digit numbers and valid for with 5 skews as set in
// the above options (5 skew = time tolerance of ± 15 seconds(period) * 5).
passcode, err := key.PassCode()
// Validate the received passcode.
ok := key.Validate(passcode)
// Get 100x100 px image of QR code as PNG byte data.
//
// FixLevelDefault is the 15% of error correction.
qrCodeObj, err := key.QRCode(totp.FixLevelDefault)
pngBytes, err := qrCodeObj.PNG(100, 100)
// Get the secret key in PEM format text.
pemKey, err := key.PEM()
// Get the secret key in TOTP URI format string.
// This is equivalent to key.String().
uriKey := key.URI()
// Retrieve the secret value in various formats.
// ---------------------------------------------
// Get the secret value in Base32 format string.
// This encoding is used in TOTP URI format and is equivalent to
// key.Secret.String().
base32Key := key.Secret.Base32()
// Get the secret value in Base62 format string.
base62Key := key.Secret.Base62()
// Get the secret value in Base64 format string.
// This encoding is used in PEM format.
base64Key := key.Secret.Base64()
// Get the secret value in bytes. This is the raw secret value.
rawKey := key.Secret.Bytes()
- View more examples and advanced usages @ pkg.go.dev
This package supports ECDH key agreement protocol for the TOTP secret key generation (deriving TOTP secret from ECDH shared secret).
// Pre-agreement between Alice and Bob. commonCtx can be any string but consistent
// between Alice and Bob.
commonCurve := ecdh.X25519()
commonCtx := "example.com [email protected] [email protected] TOTP secret v1"
// Key exchange between Alice and Bob.
alicePriv, alicePub := getECDHKeysSomeHowForAlice(commonCurve)
bobPriv, bobPub := getECDHKeysSomeHowForBob(commonCurve)
// Generate a new TOTP key for Alice using:
// - Alice's ECDH private key
// - Bob's ECDH public key
// - Alice and Bob's common context string
Issuer := "Example.com"
AccountName := "[email protected]"
key, err := totp.GenerateKey(Issuer, AccountName,
totp.WithECDH(alicePriv, bobPub, commonCtx),
)
if err != nil {
log.Fatal(err)
}
// Alice generates 6 digits of TOTP passcode which should be the same as Bob's.
passcode, err := key.PassCode()
if err != nil {
log.Fatal(err)
}
- View the full ECDH example with detailed comments | GoDoc @ pkg.go.dev
A shared secret key can be created by exchanging a public ECDH key between two parties. This shared secret key is used to derive the TOTP key. Thus the same TOTP passcode can be shared within the same time period.
This feature is useful when a shared but ephemeral/volatile secret value (a common TOTP passcode) is required to increase security between two parties.
For example, a time-based shared salt for hashing or an additional value to generate a shared secret key for symmetric encryption.
The values expire, but the possibilities are endless.
Any Pull-Request for improvement is welcome!
- Branch to PR:
main
- CONTRIBUTING.md
- CIs on PR/Push:
unit-tests
golangci-lint
codeQL-analysis
platform-tests
- Security policy
- Help wanted
- MIT, Copyright (c) 2022- The go-totp contributors.
- This Go package relies heavily on support from the
github.com/pquerna/otp
package.