clair/vendor/github.com/ziutek/mymysql/native/passwd.go
2016-02-24 16:34:54 -05:00

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[:]
}