github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/auth/mysql_native_password.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package auth 15 16 import ( 17 "bytes" 18 "crypto/sha1" //nolint: gosec 19 "encoding/hex" 20 "fmt" 21 22 "github.com/pingcap/errors" 23 "github.com/pingcap/tidb/parser/terror" 24 ) 25 26 // CheckScrambledPassword check scrambled password received from client. 27 // The new authentication is performed in following manner: 28 // 29 // SERVER: public_seed=create_random_string() 30 // send(public_seed) 31 // CLIENT: recv(public_seed) 32 // hash_stage1=sha1("password") 33 // hash_stage2=sha1(hash_stage1) 34 // reply=xor(hash_stage1, sha1(public_seed,hash_stage2) 35 // // this three steps are done in scramble() 36 // send(reply) 37 // SERVER: recv(reply) 38 // hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) 39 // candidate_hash2=sha1(hash_stage1) 40 // check(candidate_hash2==hash_stage2) 41 // // this three steps are done in check_scramble() 42 func CheckScrambledPassword(salt, hpwd, auth []byte) bool { 43 //nolint: gosec 44 crypt := sha1.New() 45 _, err := crypt.Write(salt) 46 terror.Log(errors.Trace(err)) 47 _, err = crypt.Write(hpwd) 48 terror.Log(errors.Trace(err)) 49 hash := crypt.Sum(nil) 50 // token = scrambleHash XOR stage1Hash 51 if len(auth) != len(hash) { 52 return false 53 } 54 for i := range hash { 55 hash[i] ^= auth[i] 56 } 57 58 return bytes.Equal(hpwd, Sha1Hash(hash)) 59 } 60 61 // Sha1Hash is an util function to calculate sha1 hash. 62 func Sha1Hash(bs []byte) []byte { 63 //nolint: gosec 64 crypt := sha1.New() 65 _, err := crypt.Write(bs) 66 terror.Log(errors.Trace(err)) 67 return crypt.Sum(nil) 68 } 69 70 // EncodePassword converts plaintext password(type is string) to hashed hex string. 71 func EncodePassword(pwd string) string { 72 if len(pwd) == 0 { 73 return "" 74 } 75 hash1 := Sha1Hash([]byte(pwd)) 76 hash2 := Sha1Hash(hash1) 77 78 return fmt.Sprintf("*%X", hash2) 79 } 80 81 // EncodePasswordBytes converts plaintext password(type is []byte) to hashed hex string. 82 func EncodePasswordBytes(pwd []byte) string { 83 if len(pwd) == 0 { 84 return "" 85 } 86 hash1 := Sha1Hash(pwd) 87 hash2 := Sha1Hash(hash1) 88 89 return fmt.Sprintf("*%X", hash2) 90 } 91 92 // DecodePassword converts hex string password without prefix '*' to byte array. 93 func DecodePassword(pwd string) ([]byte, error) { 94 x, err := hex.DecodeString(pwd[1:]) 95 if err != nil { 96 return nil, errors.Trace(err) 97 } 98 return x, nil 99 }