forked from Philio/GoMySQL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
password.go
112 lines (104 loc) · 2.79 KB
/
password.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// GoMySQL - A MySQL client library for Go
//
// Copyright 2010-2011 Phil Bayfield. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mysql
import (
"crypto/sha1"
"math"
)
const SCRAMBLE_LENGTH_323 = 8
// Random struct, see libmysql/password.c
type randStruct struct {
maxValue uint32
maxValueDbl float64
seed1 uint32
seed2 uint32
}
// Initialise rand struct, see libmysql/password.c
func randominit(seed1, seed2 uint32) *randStruct {
return &randStruct{
maxValue: 0x3FFFFFFF,
maxValueDbl: 0x3FFFFFFF,
seed1: seed1 % 0x3FFFFFFF,
seed2: seed2 % 0x3FFFFFFF,
}
}
// Generate a random number, see libmysql/password.c
func (r *randStruct) myRnd() float64 {
r.seed1 = (r.seed1*3 + r.seed2) % r.maxValue
r.seed2 = (r.seed1 + r.seed2 + 33) % r.maxValue
return float64(r.seed1) / r.maxValueDbl
}
// Password hash used in pre-4.1, see libmysql/password.c
func hashPassword(password []byte) []uint32 {
nr := uint32(1345345333)
add := uint32(7)
nr2 := uint32(0x12345671)
for i := 0; i < len(password); i++ {
if password[i] == ' ' || password[i] == '\t' {
continue
}
tmp := uint32(password[i])
nr ^= (((nr & 63) + add) * tmp) + (nr << 8)
nr2 += (nr2 << 8) ^ nr
add += tmp
}
result := make([]uint32, 2)
result[0] = nr & ((1 << 31) - 1)
result[1] = nr2 & ((1 << 31) - 1)
return result
}
// Encrypt password the pre-4.1 way, see libmysql/password.c
func scramble323(message, password []byte) (result []byte) {
if len(password) == 0 {
return
}
// Check message is no longer than max length
if len(message) > SCRAMBLE_LENGTH_323 {
message = message[:SCRAMBLE_LENGTH_323]
}
// Generate hashes
hashPass := hashPassword(password)
hashMessage := hashPassword(message)
// Initialise random struct
rand := randominit(hashPass[0]^hashMessage[0], hashPass[1]^hashMessage[1])
// Generate result
result = make([]byte, SCRAMBLE_LENGTH_323)
for i := 0; i < SCRAMBLE_LENGTH_323; i++ {
result[i] = byte(math.Floor(rand.myRnd()*31) + 64)
}
extra := byte(math.Floor(rand.myRnd() * 31))
for i := 0; i < SCRAMBLE_LENGTH_323; i++ {
result[i] ^= extra
}
return
}
// Encrypt password using 4.1+ method
func scramble41(message, password []byte) (result []byte) {
if len(password) == 0 {
return
}
// stage1_hash = SHA1(password)
// SHA1 encode
crypt := sha1.New()
crypt.Write(password)
stg1Hash := crypt.Sum()
// token = SHA1(SHA1(stage1_hash), scramble) XOR stage1_hash
// SHA1 encode again
crypt.Reset()
crypt.Write(stg1Hash)
stg2Hash := crypt.Sum()
// SHA1 2nd hash and scramble
crypt.Reset()
crypt.Write(message)
crypt.Write(stg2Hash)
stg3Hash := crypt.Sum()
// XOR with first hash
result = make([]byte, 20)
for i := range result {
result[i] = stg3Hash[i] ^ stg1Hash[i]
}
return
}