100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package auth
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1" //nolint: gosec
|
|
"encoding/hex"
|
|
"fmt"
|
|
|
|
"github.com/pingcap/errors"
|
|
"github.com/pingcap/tidb/pkg/parser/terror"
|
|
)
|
|
|
|
// CheckScrambledPassword check scrambled password received from client.
|
|
// The new authentication is performed in following manner:
|
|
//
|
|
// SERVER: public_seed=create_random_string()
|
|
// send(public_seed)
|
|
// CLIENT: recv(public_seed)
|
|
// hash_stage1=sha1("password")
|
|
// hash_stage2=sha1(hash_stage1)
|
|
// reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
|
// // this three steps are done in scramble()
|
|
// send(reply)
|
|
// SERVER: recv(reply)
|
|
// hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
|
// candidate_hash2=sha1(hash_stage1)
|
|
// check(candidate_hash2==hash_stage2)
|
|
// // this three steps are done in check_scramble()
|
|
func CheckScrambledPassword(salt, hpwd, auth []byte) bool {
|
|
//nolint: gosec
|
|
crypt := sha1.New()
|
|
_, err := crypt.Write(salt)
|
|
terror.Log(errors.Trace(err))
|
|
_, err = crypt.Write(hpwd)
|
|
terror.Log(errors.Trace(err))
|
|
hash := crypt.Sum(nil)
|
|
// token = scrambleHash XOR stage1Hash
|
|
if len(auth) != len(hash) {
|
|
return false
|
|
}
|
|
for i := range hash {
|
|
hash[i] ^= auth[i]
|
|
}
|
|
|
|
return bytes.Equal(hpwd, Sha1Hash(hash))
|
|
}
|
|
|
|
// Sha1Hash is an util function to calculate sha1 hash.
|
|
func Sha1Hash(bs []byte) []byte {
|
|
//nolint: gosec
|
|
crypt := sha1.New()
|
|
_, err := crypt.Write(bs)
|
|
terror.Log(errors.Trace(err))
|
|
return crypt.Sum(nil)
|
|
}
|
|
|
|
// EncodePassword converts plaintext password(type is string) to hashed hex string.
|
|
func EncodePassword(pwd string) string {
|
|
if len(pwd) == 0 {
|
|
return ""
|
|
}
|
|
hash1 := Sha1Hash([]byte(pwd))
|
|
hash2 := Sha1Hash(hash1)
|
|
|
|
return fmt.Sprintf("*%X", hash2)
|
|
}
|
|
|
|
// EncodePasswordBytes converts plaintext password(type is []byte) to hashed hex string.
|
|
func EncodePasswordBytes(pwd []byte) string {
|
|
if len(pwd) == 0 {
|
|
return ""
|
|
}
|
|
hash1 := Sha1Hash(pwd)
|
|
hash2 := Sha1Hash(hash1)
|
|
|
|
return fmt.Sprintf("*%X", hash2)
|
|
}
|
|
|
|
// DecodePassword converts hex string password without prefix '*' to byte array.
|
|
func DecodePassword(pwd string) ([]byte, error) {
|
|
x, err := hex.DecodeString(pwd[1:])
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
return x, nil
|
|
}
|