totp.go 912 B

123456789101112131415161718192021222324252627282930
  1. package fwh_pro
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha1"
  5. "encoding/base32"
  6. "encoding/binary"
  7. "fmt"
  8. "strings"
  9. "time"
  10. )
  11. // generateTOTP implements RFC 6238 with the common SHA-1, 6-digit, 30-second profile.
  12. func generateTOTP(secret string, now time.Time) (string, error) {
  13. secret = strings.ToUpper(strings.Join(strings.Fields(secret), ""))
  14. secret = strings.TrimRight(secret, "=")
  15. key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
  16. if err != nil || len(key) == 0 {
  17. return "", fmt.Errorf("invalid FWH TOTP secret: expected a Base32 key")
  18. }
  19. var counter [8]byte
  20. binary.BigEndian.PutUint64(counter[:], uint64(now.Unix()/30))
  21. mac := hmac.New(sha1.New, key)
  22. _, _ = mac.Write(counter[:])
  23. digest := mac.Sum(nil)
  24. offset := digest[len(digest)-1] & 0x0f
  25. value := binary.BigEndian.Uint32(digest[offset:offset+4]) & 0x7fffffff
  26. return fmt.Sprintf("%06d", value%1000000), nil
  27. }