Documentation ¶
Overview ¶
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { // Generate a new secret key Issuer := "Example.com" AccountName := "alice@example.com" key, err := totp.GenerateKey(Issuer, AccountName) if err != nil { log.Fatal(err) } // Generate 6 digits passcode (valid for 30 seconds) passcode, err := key.PassCode() if err != nil { log.Fatal(err) } // Validate the passcode valid, err := key.Validate(passcode) if err != nil { log.Fatal(err) } if valid { fmt.Println("Passcode is valid") } }
Output: Passcode is valid
Example (Advanced) ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { // Options to generate a new key. The secret will be generated randomly. opts := totp.Options{ Issuer: "Example.com", AccountName: "alice@example.com", Algorithm: totp.Algorithm("SHA1"), // Choices are: MD5, SHA1, SHA256 and SHA512 Period: 60, // Validity period in seconds SecretSize: 20, // Secret key size in bytes Skew: 0, // Number of periods before or after the current time to allow. Digits: totp.Digits(8), // Choices are: 6 and 8 } // Generate a new secret key key, err := totp.GenerateKeyCustom(opts) if err != nil { log.Fatal(err) } // Generate 8 digits passcode that are valid for 60 seconds (see options above) passcode, err := key.PassCode() if err != nil { log.Fatal(err) } // Validate the passcode valid, err := key.Validate(passcode) if err != nil { log.Fatal(err) } if valid { fmt.Println("Passcode is valid") } }
Output: Passcode is valid
Index ¶
- Constants
- type Algorithm
- type Digits
- type Key
- type Options
- type Secret
- type URI
- func (u URI) AccountName() string
- func (u URI) Algorithm() string
- func (u URI) Check() error
- func (u URI) Digits() uint
- func (u URI) Host() string
- func (u URI) Issuer() string
- func (u URI) IssuerFromPath() string
- func (u URI) Path() string
- func (u URI) Period() uint
- func (u URI) Scheme() string
- func (u URI) Secret() Secret
- func (u URI) String() string
Examples ¶
Constants ¶
const ( OptionAlgorithmDefault = Algorithm("SHA512") // Default algorithm OptionPeriodDefault = uint(30) // Seconds (rfc6238) OptionSecretSizeDefault = uint(20) // Bytes OptionSkewDefault = uint(0) // Periods OptionDigitsDefault = Digits(6) // Six digits )
Constants for the default values of the options.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Algorithm ¶
type Algorithm string
Algorithm is a string that represents the algorithm used for HMAC.
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { // Create a new Algorithm object from a string. Choices are: // MD5, SHA1, SHA256 and SHA512. algo, err := totp.NewAlgorithmStr("SHA512") if err != nil { log.Fatal(err) } fmt.Println("Algorithm:", algo.String()) fmt.Println("Algorithm ID:", algo.ID()) fmt.Printf("Type: %T\n", algo.OTPAlgorithm()) }
Output: Algorithm: SHA512 Algorithm ID: 2 Type: otp.Algorithm
func NewAlgorithmID ¶
NewAlgorithmID creates a new Algorithm object from an int.
func NewAlgorithmStr ¶
NewAlgorithmStr creates a new Algorithm object from a string. Choices are: MD5, SHA1, SHA256 and SHA512.
func (Algorithm) ID ¶
ID returns the ID of the algorithm which is the same int value as the original OTP library.
Undefined ID will always return 2 (SHA512).
func (Algorithm) IsSupported ¶
IsSupported returns true if the algorithm is supported.
Example ¶
package main import ( "fmt" "github.com/KEINOS/go-totp/totp" ) func main() { // Cast a string to Algorithm type algo := totp.Algorithm("BLAKE3") // Check if the algorithm is supported if algo.IsSupported() { fmt.Println("Algorithm is supported") } else { fmt.Println("Algorithm is not supported") } }
Output: Algorithm is not supported
func (Algorithm) OTPAlgorithm ¶
OTPAlgorithm is similar to ID() but returns in the original type of the OTP library.
Undefined Algorithm type will always return `otp.AlgorithmSHA512`.
type Digits ¶
type Digits uint
Digits represents the number of digits present in the user's OTP passcode. Six and Eight are the most common values.
Example ¶
package main import ( "fmt" "github.com/KEINOS/go-totp/totp" ) func main() { // Create a new Digits object from a number. Choices are: // 6 and 8. digits := totp.NewDigits(8) fmt.Println("Digits:", digits) fmt.Println("Digits ID:", digits.OTPDigits()) // DigitsEight is equivalent to NewDigits(8) if totp.DigitsEight == totp.NewDigits(8) { fmt.Println("Digit 8", "OK") } // DigitsSix is equivalent to NewDigits(6) if totp.DigitsSix == totp.NewDigits(6) { fmt.Println("Digit 6", "OK") } }
Output: Digits: 8 Digits ID: 8 Digit 8 OK Digit 6 OK
type Key ¶
Key is a struct that holds the TOTP secret and its options.
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { // Generate a new secret key Issuer := "Example.com" AccountName := "alice@example.com" key, err := totp.GenerateKey(Issuer, AccountName) if err != nil { log.Fatal(err) } fmt.Println("Issuer:", key.Options.AccountName) fmt.Println("AccountName:", key.Options.AccountName) }
Output: Issuer: alice@example.com AccountName: alice@example.com
func GenerateKey ¶
GenerateKey creates a new Key object with default options. Which is:
SHA-512 hash for HMAC, 30 seconds of period, 64 byte size of secret and 6 digits of passcode.
To specify custom options, use GenerateKeyCustom().
func GenerateKeyCustom ¶
GenerateKeyCustom creates a new Key object with custom options. With this function you can specify the algorithm, period, secret size and digits.
func GenerateKeyURI ¶
GenerateKeyURI creates a new Key object from an TOTP uri/url.
The URL format is documented here:
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { origin := "otpauth://totp/Example.com:alice@example.com?algorithm=SHA1&" + "digits=12&issuer=Example.com&period=60&secret=QF7N673VMVHYWATKICRUA7V5MUGFG3Z3" key, err := totp.GenerateKeyURI(origin) if err != nil { log.Fatal(err) } fmt.Println("Issuer:", key.Options.Issuer) fmt.Println("AccountName:", key.Options.AccountName) fmt.Println("Algorithm:", key.Options.Algorithm) fmt.Println("Digits:", key.Options.Digits) fmt.Println("Period:", key.Options.Period) fmt.Println("Secret Size:", key.Options.SecretSize) fmt.Println("Secret:", key.Secret.String()) }
Output: Issuer: Example.com AccountName: alice@example.com Algorithm: SHA1 Digits: 12 Period: 60 Secret Size: 20 Secret: QF7N673VMVHYWATKICRUA7V5MUGFG3Z3
type Options ¶
type Options struct { // Name of the secret issuer. (eg, organization, company, domain) Issuer string // Name of the User's Account. (eg, email address) AccountName string // Algorithm to use for HMAC. (Default: SHA512) Algorithm Algorithm // Number of seconds a TOTP hash is valid for. (Default: 30 seconds) Period uint // Size in size of the generated Secret. (Default: 20 bytes) SecretSize uint // Skew is the periods before or after the current time to allow. // Value of 1 allows up to Period of either side of the specified time. // Defaults to 0 allowed skews. Values greater than 1 are likely sketchy. Skew uint // Digits to request. DigitsSix or DigitsEight. (Default: DigitsSix) Digits Digits }
Options is a struct that holds the options for a TOTP key.
Example ¶
package main import ( "fmt" "github.com/KEINOS/go-totp/totp" ) func main() { //nolint:exhaustruct // allow missing fields options := totp.Options{ Issuer: "Example.com", AccountName: "alice@example.com", } options.SetDefault() // Issuer is the name of the service who issued the secret. fmt.Println("Issuer:", options.Issuer) // Name of the owner of the secret key. fmt.Println("AccountName:", options.AccountName) // Hash algorithm to generate the passcode as HMAC. fmt.Println("Algorithm:", options.Algorithm) // Length of the passcode. fmt.Println("Digits:", options.Digits) // Valid seconds of passcode issued. fmt.Println("Period:", options.Period) // Size of the secret key in bytes. fmt.Println("Secret Size:", options.SecretSize) // Skew is an acceptable range of time before and after. Value of 1 allows // up to Period of either side of the specified time. fmt.Println("Skew:", options.Skew) }
Output: Issuer: Example.com AccountName: alice@example.com Algorithm: SHA512 Digits: 6 Period: 30 Secret Size: 20 Skew: 0
func (*Options) SetDefault ¶
func (opts *Options) SetDefault()
SetDefault sets the undefined options to its default value.
type Secret ¶
type Secret []byte
Secret is a byte slice that represents a secret key.
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { // The below two lines are the same but with different base-encodings. //nolint:gosec // potentially hardcoded credentials for testing base32Secret := "MZXW6IDCMFZCAYTVPJ5A" //nolint:gosec // potentially hardcoded credentials for testing base62Secret := "FegjEGvm7g03GQye" // Instantiate a new Secret object from a base32 encoded string. secret32, err := totp.NewSecretBase32(base32Secret) if err != nil { log.Fatal(err) } // Instantiate a new Secret object from a base62 encoded string. secret62, err := totp.NewSecretBase62(base62Secret) if err != nil { log.Fatal(err) } // Once instantiated, you can use the Secret object to get the secret in // different base-encodings. fmt.Println("Get as base62 encoded string:", secret32.Base62()) fmt.Println("Get as base32 encoded string:", secret62.Base32()) // String() method is equivalent to Base32() if secret62.String() == secret62.Base32() { fmt.Println("String() is equivalent to Base32()") } if secret32.String() == secret62.String() { fmt.Println("Two secrets are the same.") } }
Output: Get as base62 encoded string: FegjEGvm7g03GQye Get as base32 encoded string: MZXW6IDCMFZCAYTVPJ5A String() is equivalent to Base32() Two secrets are the same.
func NewSecretBase32 ¶
NewSecretBase32 creates a new Secret object from a base32 encoded string.
func NewSecretBase62 ¶
NewSecretBase62 creates a new Secret object from a base62 encoded string.
func NewSecretBytes ¶
NewSecretBytes creates a new Secret object from a byte slice.
Example ¶
package main import ( "fmt" "github.com/KEINOS/go-totp/totp" ) func main() { data := []byte("some secret") // Generate a new Secret object from a byte slice. secret := totp.NewSecretBytes(data) fmt.Printf("Type: %T\n", secret) fmt.Printf("Value: %#v\n", secret) fmt.Println("Secret bytes:", secret.Bytes()) fmt.Println("Secret string:", secret.String()) fmt.Println("Secret Base32:", secret.Base32()) fmt.Println("Secret Base62:", secret.Base62()) }
Output: Type: totp.Secret Value: totp.Secret{0x73, 0x6f, 0x6d, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74} Secret bytes: [115 111 109 101 32 115 101 99 114 101 116] Secret string: ONXW2ZJAONSWG4TFOQ Secret Base32: ONXW2ZJAONSWG4TFOQ Secret Base62: bfF9D3ygDyVQZp2
func (Secret) Base32 ¶
Base32 returns the secret as a base32 encoded string. Which is the standard format used by TOTP URIs.
type URI ¶
type URI string
URI is a struct that holds the TOTP URI.
All methods are calculated each time they are called. Therefore, it is recommended to store them. Note also that the values are not validated. For example, "Digits" may return any value.
Example ¶
package main import ( "fmt" "log" "github.com/KEINOS/go-totp/totp" ) func main() { origin := "otpauth://totp/Example.com:alice@example.com?algorithm=SHA1&" + "digits=12&issuer=Example.com&period=60&secret=QF7N673VMVHYWATKICRUA7V5MUGFG3Z3" uri := totp.URI(origin) // Check if the URI is correctly formatted with the required fields. if err := uri.Check(); err != nil { log.Fatal(err) } if uri.String() == origin { fmt.Println("Raw URI and String is equal: OK") } fmt.Println("Scheme:", uri.Scheme()) fmt.Println("Host:", uri.Host()) fmt.Println("Issuer:", uri.Issuer()) fmt.Println("Account Name:", uri.AccountName()) fmt.Println("Algorithm:", uri.Algorithm()) fmt.Println("Secret:", uri.Secret().String()) fmt.Println("Period:", uri.Period()) fmt.Println("Digits:", uri.Digits()) }
Output: Raw URI and String is equal: OK Scheme: otpauth Host: totp Issuer: Example.com Account Name: alice@example.com Algorithm: SHA1 Secret: QF7N673VMVHYWATKICRUA7V5MUGFG3Z3 Period: 60 Digits: 12
func NewURI ¶
NewURI returns a new URI object. It simply returns the casted string as a URI object. To validate if the URI is correctly formatted, use the Check() method.
func (URI) AccountName ¶
AccountName returns the account name from the URI.
func (URI) Check ¶
Check returns true if the URI is correctly formatted and required fields are set.
func (URI) Issuer ¶
Issuer returns the issuer from the URI. Similar to IssuerFromPath() but returns the issuer from the query string instead of the path.
func (URI) IssuerFromPath ¶
IssuerFromPath returns the issuer from the URI. Similar to Issuer() but returns the issuer from the path instead of the query string.
Example ¶
package main import ( "fmt" "github.com/KEINOS/go-totp/totp" ) func main() { origin := "otpauth://totp/Example.com:alice@example.com?issuer=Wrong.com" uri := totp.URI(origin) fmt.Println(uri.IssuerFromPath()) }
Output: Example.com
func (URI) Path ¶
Path returns the path from the URI. Which is used as a "label" for the TOTP. See:
https://github.com/google/google-authenticator/wiki/Key-Uri-Format#label
func (URI) Period ¶
Period returns the number of seconds a TOTP hash is valid for from the URI. If the period is not set or the URL is invalid, it returns 0.