authcode.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package util
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "crypto/sha1"
  6. "encoding/base32"
  7. "encoding/binary"
  8. "fmt"
  9. "strings"
  10. "time"
  11. )
  12. type GoogleAuth struct {
  13. }
  14. func NewGoogleAuth() *GoogleAuth {
  15. return &GoogleAuth{}
  16. }
  17. func (this *GoogleAuth) Remain() int {
  18. return 60 - time.Now().Second()
  19. }
  20. func (this *GoogleAuth) un() int64 {
  21. return time.Now().Unix() / 60
  22. }
  23. func (this *GoogleAuth) hmacSha1(key, data []byte) []byte {
  24. h := hmac.New(sha1.New, key)
  25. if total := len(data); total > 0 {
  26. h.Write(data)
  27. }
  28. return h.Sum(nil)
  29. }
  30. func (this *GoogleAuth) base32encode(src []byte) string {
  31. return base32.StdEncoding.EncodeToString(src)
  32. }
  33. func (this *GoogleAuth) base32decode(s string) ([]byte, error) {
  34. return base32.StdEncoding.DecodeString(s)
  35. }
  36. func (this *GoogleAuth) toBytes(value int64) []byte {
  37. var result []byte
  38. mask := int64(0xFF)
  39. shifts := [8]uint16{56, 48, 40, 32, 24, 16, 8, 0}
  40. for _, shift := range shifts {
  41. result = append(result, byte((value>>shift)&mask))
  42. }
  43. return result
  44. }
  45. func (this *GoogleAuth) toUint32(bts []byte) uint32 {
  46. return (uint32(bts[0]) << 24) + (uint32(bts[1]) << 16) +
  47. (uint32(bts[2]) << 8) + uint32(bts[3])
  48. }
  49. func (this *GoogleAuth) oneTimePassword(key []byte, data []byte) uint32 {
  50. hash := this.hmacSha1(key, data)
  51. offset := hash[len(hash)-1] & 0x0F
  52. hashParts := hash[offset : offset+4]
  53. hashParts[0] = hashParts[0] & 0x7F
  54. number := this.toUint32(hashParts)
  55. return number % 1000000
  56. }
  57. func (this *GoogleAuth) GetSecret() string {
  58. var buf bytes.Buffer
  59. binary.Write(&buf, binary.BigEndian, this.un())
  60. return strings.ToUpper(this.base32encode(this.hmacSha1(buf.Bytes(), nil)))
  61. }
  62. func (this *GoogleAuth) GetCode(secret string) (string, error) {
  63. secretUpper := strings.ToUpper(secret)
  64. secretKey, err := this.base32decode(secretUpper)
  65. if err != nil {
  66. return "", err
  67. }
  68. number := this.oneTimePassword(secretKey, this.toBytes(time.Now().Unix()/60))
  69. return fmt.Sprintf("%06d", number), nil
  70. }
  71. func (this *GoogleAuth) VerifyCode(secret, code string) (bool, error) {
  72. _code, err := this.GetCode(secret)
  73. fmt.Println(_code, code)
  74. if err != nil {
  75. return false, err
  76. }
  77. return _code == code, nil
  78. }