109 lines
2.6 KiB
Go
109 lines
2.6 KiB
Go
package native
|
|
|
|
import (
|
|
"crypto/sha1"
|
|
"math"
|
|
)
|
|
|
|
// Borrowed from GoMySQL
|
|
// SHA1(SHA1(SHA1(password)), scramble) XOR SHA1(password)
|
|
func encryptedPasswd(password string, scramble []byte) (out []byte) {
|
|
if len(password) == 0 {
|
|
return
|
|
}
|
|
// stage1_hash = SHA1(password)
|
|
// SHA1 encode
|
|
crypt := sha1.New()
|
|
crypt.Write([]byte(password))
|
|
stg1Hash := crypt.Sum(nil)
|
|
// token = SHA1(SHA1(stage1_hash), scramble) XOR stage1_hash
|
|
// SHA1 encode again
|
|
crypt.Reset()
|
|
crypt.Write(stg1Hash)
|
|
stg2Hash := crypt.Sum(nil)
|
|
// SHA1 2nd hash and scramble
|
|
crypt.Reset()
|
|
crypt.Write(scramble)
|
|
crypt.Write(stg2Hash)
|
|
stg3Hash := crypt.Sum(nil)
|
|
// XOR with first hash
|
|
out = make([]byte, len(scramble))
|
|
for ii := range scramble {
|
|
out[ii] = stg3Hash[ii] ^ stg1Hash[ii]
|
|
}
|
|
return
|
|
}
|
|
|
|
// Old password handling based on translating to Go some functions from
|
|
// libmysql
|
|
|
|
// The main idea is that no password are sent between client & server on
|
|
// connection and that no password are saved in mysql in a decodable form.
|
|
//
|
|
// On connection a random string is generated and sent to the client.
|
|
// The client generates a new string with a random generator inited with
|
|
// the hash values from the password and the sent string.
|
|
// This 'check' string is sent to the server where it is compared with
|
|
// a string generated from the stored hash_value of the password and the
|
|
// random string.
|
|
|
|
// libmysql/my_rnd.c
|
|
type myRnd struct {
|
|
seed1, seed2 uint32
|
|
}
|
|
|
|
const myRndMaxVal = 0x3FFFFFFF
|
|
|
|
func newMyRnd(seed1, seed2 uint32) *myRnd {
|
|
r := new(myRnd)
|
|
r.seed1 = seed1 % myRndMaxVal
|
|
r.seed2 = seed2 % myRndMaxVal
|
|
return r
|
|
}
|
|
|
|
func (r *myRnd) Float64() float64 {
|
|
r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
|
|
r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
|
|
return float64(r.seed1) / myRndMaxVal
|
|
}
|
|
|
|
// libmysql/password.c
|
|
func pwHash(password []byte) (result [2]uint32) {
|
|
var nr, add, nr2, tmp uint32
|
|
nr, add, nr2 = 1345345333, 7, 0x12345671
|
|
|
|
for _, c := range password {
|
|
if c == ' ' || c == '\t' {
|
|
continue // skip space in password
|
|
}
|
|
|
|
tmp = uint32(c)
|
|
nr ^= (((nr & 63) + add) * tmp) + (nr << 8)
|
|
nr2 += (nr2 << 8) ^ nr
|
|
add += tmp
|
|
}
|
|
|
|
result[0] = nr & ((1 << 31) - 1) // Don't use sign bit (str2int)
|
|
result[1] = nr2 & ((1 << 31) - 1)
|
|
return
|
|
}
|
|
|
|
func encryptedOldPassword(password string, scramble []byte) []byte {
|
|
if len(password) == 0 {
|
|
return nil
|
|
}
|
|
scramble = scramble[:8]
|
|
hashPw := pwHash([]byte(password))
|
|
hashSc := pwHash(scramble)
|
|
r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
|
|
var out [8]byte
|
|
for i := range out {
|
|
out[i] = byte(math.Floor(r.Float64()*31) + 64)
|
|
}
|
|
extra := byte(math.Floor(r.Float64() * 31))
|
|
for i := range out {
|
|
out[i] ^= extra
|
|
}
|
|
return out[:]
|
|
}
|