authentication.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package binlog
  2. import (
  3. "bytes"
  4. "crypto/sha1"
  5. "crypto/sha256"
  6. )
  7. // Sha2RequestPublicKey is a constant in the MySQL Protocol.
  8. const Sha2RequestPublicKey = 0x02
  9. // Sha2FastAuthSuccess is a constant in the MySQL Protocol.
  10. const Sha2FastAuthSuccess = 0x03
  11. // Sha2PerformFullAuthentication is a constant in the MySQL protocol.
  12. const Sha2PerformFullAuthentication = 0x04
  13. // AuthMoreDataPacket represnts a MySQL auth-more packet.
  14. type AuthMoreDataPacket struct {
  15. *PacketHeader
  16. Data uint64
  17. }
  18. func (c *Conn) decodeAuthMoreDataResponsePacket(ph *PacketHeader) (*AuthMoreDataPacket, error) {
  19. md := AuthMoreDataPacket{}
  20. md.PacketHeader = ph
  21. md.Data = c.getInt(TypeFixedInt, 1)
  22. err := c.scanner.Err()
  23. if err != nil {
  24. return nil, err
  25. }
  26. return &md, nil
  27. }
  28. // AuthResponsePacket represents a MySQL authentication response packet.
  29. type AuthResponsePacket struct {
  30. PacketLength uint64
  31. SequenceID uint64
  32. Status uint64
  33. PluginName string
  34. AuthPluginData *bytes.Buffer
  35. }
  36. func (c *Conn) decodeAuthResponsePacket() (*AuthResponsePacket, error) {
  37. packet := AuthResponsePacket{}
  38. packet.PacketLength = c.getInt(TypeFixedInt, 3)
  39. packet.SequenceID = c.getInt(TypeFixedInt, 1)
  40. packet.Status = c.getInt(TypeFixedInt, 1)
  41. packet.PluginName = c.getString(TypeNullTerminatedString, 0)
  42. packet.AuthPluginData = c.readBytes(20)
  43. err := c.scanner.Err()
  44. if err != nil {
  45. return nil, err
  46. }
  47. return &packet, err
  48. }
  49. func (c *Conn) writeAuthSwitchPacket(ap *AuthResponsePacket) error {
  50. salt := ap.AuthPluginData.Bytes()
  51. password := []byte(c.HandshakeResponse.AuthResponse)
  52. c.authenticate(salt, password)
  53. if c.Flush() != nil {
  54. return c.Flush()
  55. }
  56. return nil
  57. }
  58. func (c *Conn) authenticate(salt []byte, password []byte) {
  59. var ar []byte
  60. salt = salt[:20] // trim null byte from end.
  61. switch c.Handshake.AuthPluginName {
  62. case "mysql_native_password":
  63. ar = c.nativeSha1Auth(salt, password)
  64. case "caching_sha2_password":
  65. ar = c.cachingSha2Auth(salt, password)
  66. }
  67. hr := c.HandshakeResponse
  68. hr.AuthResponseLength = uint64(len(ar))
  69. if hr.ClientFlag.PluginAuthLenEncClientData {
  70. c.putInt(TypeLenEncInt, hr.AuthResponseLength, 0)
  71. c.putBytes(ar)
  72. } else if hr.ClientFlag.SecureConnection {
  73. c.putInt(TypeFixedInt, hr.AuthResponseLength, 1)
  74. c.putBytes(ar)
  75. } else {
  76. c.putString(TypeNullTerminatedString, string(ar))
  77. }
  78. }
  79. func (c *Conn) nativeSha1Auth(salt []byte, password []byte) []byte {
  80. if len(password) < 1 {
  81. return nil
  82. }
  83. pHash := c.sha1Hash(password)
  84. pHashHash := c.sha1Hash(pHash)
  85. spHash := c.sha1Hash(append(salt, pHashHash...))
  86. for i := range pHash {
  87. pHash[i] ^= spHash[i]
  88. }
  89. return pHash
  90. }
  91. func (c *Conn) cachingSha2Auth(salt []byte, password []byte) []byte {
  92. if len(password) < 1 {
  93. return nil
  94. }
  95. pHash := c.sha256Hash(password)
  96. pHashHash := c.sha256Hash(pHash)
  97. pHashHashHash := c.sha256Hash(pHashHash)
  98. authData := c.sha256Hash(append(pHashHashHash, salt...))
  99. for i := range pHash {
  100. pHash[i] ^= authData[i]
  101. }
  102. return pHash
  103. }
  104. func (c *Conn) sha1Hash(word []byte) []byte {
  105. s := sha1.New()
  106. s.Write(word)
  107. return s.Sum(nil)
  108. }
  109. func (c *Conn) sha256Hash(word []byte) []byte {
  110. s := sha256.New()
  111. s.Write(word)
  112. return s.Sum(nil)
  113. }