| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package binlog
- import (
- "bytes"
- "crypto/sha1"
- "crypto/sha256"
- )
- // Sha2RequestPublicKey is a constant in the MySQL Protocol.
- const Sha2RequestPublicKey = 0x02
- // Sha2FastAuthSuccess is a constant in the MySQL Protocol.
- const Sha2FastAuthSuccess = 0x03
- // Sha2PerformFullAuthentication is a constant in the MySQL protocol.
- const Sha2PerformFullAuthentication = 0x04
- // AuthMoreDataPacket represnts a MySQL auth-more packet.
- type AuthMoreDataPacket struct {
- *PacketHeader
- Data uint64
- }
- func (c *Conn) decodeAuthMoreDataResponsePacket(ph *PacketHeader) (*AuthMoreDataPacket, error) {
- md := AuthMoreDataPacket{}
- md.PacketHeader = ph
- md.Data = c.getInt(TypeFixedInt, 1)
- err := c.scanner.Err()
- if err != nil {
- return nil, err
- }
- return &md, nil
- }
- // AuthResponsePacket represents a MySQL authentication response packet.
- type AuthResponsePacket struct {
- PacketLength uint64
- SequenceID uint64
- Status uint64
- PluginName string
- AuthPluginData *bytes.Buffer
- }
- func (c *Conn) decodeAuthResponsePacket() (*AuthResponsePacket, error) {
- packet := AuthResponsePacket{}
- packet.PacketLength = c.getInt(TypeFixedInt, 3)
- packet.SequenceID = c.getInt(TypeFixedInt, 1)
- packet.Status = c.getInt(TypeFixedInt, 1)
- packet.PluginName = c.getString(TypeNullTerminatedString, 0)
- packet.AuthPluginData = c.readBytes(20)
- err := c.scanner.Err()
- if err != nil {
- return nil, err
- }
- return &packet, err
- }
- func (c *Conn) writeAuthSwitchPacket(ap *AuthResponsePacket) error {
- salt := ap.AuthPluginData.Bytes()
- password := []byte(c.HandshakeResponse.AuthResponse)
- c.authenticate(salt, password)
- if c.Flush() != nil {
- return c.Flush()
- }
- return nil
- }
- func (c *Conn) authenticate(salt []byte, password []byte) {
- var ar []byte
- salt = salt[:20] // trim null byte from end.
- switch c.Handshake.AuthPluginName {
- case "mysql_native_password":
- ar = c.nativeSha1Auth(salt, password)
- case "caching_sha2_password":
- ar = c.cachingSha2Auth(salt, password)
- }
- hr := c.HandshakeResponse
- hr.AuthResponseLength = uint64(len(ar))
- if hr.ClientFlag.PluginAuthLenEncClientData {
- c.putInt(TypeLenEncInt, hr.AuthResponseLength, 0)
- c.putBytes(ar)
- } else if hr.ClientFlag.SecureConnection {
- c.putInt(TypeFixedInt, hr.AuthResponseLength, 1)
- c.putBytes(ar)
- } else {
- c.putString(TypeNullTerminatedString, string(ar))
- }
- }
- func (c *Conn) nativeSha1Auth(salt []byte, password []byte) []byte {
- if len(password) < 1 {
- return nil
- }
- pHash := c.sha1Hash(password)
- pHashHash := c.sha1Hash(pHash)
- spHash := c.sha1Hash(append(salt, pHashHash...))
- for i := range pHash {
- pHash[i] ^= spHash[i]
- }
- return pHash
- }
- func (c *Conn) cachingSha2Auth(salt []byte, password []byte) []byte {
- if len(password) < 1 {
- return nil
- }
- pHash := c.sha256Hash(password)
- pHashHash := c.sha256Hash(pHash)
- pHashHashHash := c.sha256Hash(pHashHash)
- authData := c.sha256Hash(append(pHashHashHash, salt...))
- for i := range pHash {
- pHash[i] ^= authData[i]
- }
- return pHash
- }
- func (c *Conn) sha1Hash(word []byte) []byte {
- s := sha1.New()
- s.Write(word)
- return s.Sum(nil)
- }
- func (c *Conn) sha256Hash(word []byte) []byte {
- s := sha256.New()
- s.Write(word)
- return s.Sum(nil)
- }
|