passwd.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package native
  2. import (
  3. "crypto/sha1"
  4. "math"
  5. )
  6. // Borrowed from GoMySQL
  7. // SHA1(SHA1(SHA1(password)), scramble) XOR SHA1(password)
  8. func encryptedPasswd(password string, scramble []byte) (out []byte) {
  9. if len(password) == 0 {
  10. return
  11. }
  12. // stage1_hash = SHA1(password)
  13. // SHA1 encode
  14. crypt := sha1.New()
  15. crypt.Write([]byte(password))
  16. stg1Hash := crypt.Sum(nil)
  17. // token = SHA1(SHA1(stage1_hash), scramble) XOR stage1_hash
  18. // SHA1 encode again
  19. crypt.Reset()
  20. crypt.Write(stg1Hash)
  21. stg2Hash := crypt.Sum(nil)
  22. // SHA1 2nd hash and scramble
  23. crypt.Reset()
  24. crypt.Write(scramble)
  25. crypt.Write(stg2Hash)
  26. stg3Hash := crypt.Sum(nil)
  27. // XOR with first hash
  28. out = make([]byte, len(scramble))
  29. for ii := range scramble {
  30. out[ii] = stg3Hash[ii] ^ stg1Hash[ii]
  31. }
  32. return
  33. }
  34. // Old password handling based on translating to Go some functions from
  35. // libmysql
  36. // The main idea is that no password are sent between client & server on
  37. // connection and that no password are saved in mysql in a decodable form.
  38. //
  39. // On connection a random string is generated and sent to the client.
  40. // The client generates a new string with a random generator inited with
  41. // the hash values from the password and the sent string.
  42. // This 'check' string is sent to the server where it is compared with
  43. // a string generated from the stored hash_value of the password and the
  44. // random string.
  45. // libmysql/my_rnd.c
  46. type myRnd struct {
  47. seed1, seed2 uint32
  48. }
  49. const myRndMaxVal = 0x3FFFFFFF
  50. func newMyRnd(seed1, seed2 uint32) *myRnd {
  51. r := new(myRnd)
  52. r.seed1 = seed1 % myRndMaxVal
  53. r.seed2 = seed2 % myRndMaxVal
  54. return r
  55. }
  56. func (r *myRnd) Float64() float64 {
  57. r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
  58. r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
  59. return float64(r.seed1) / myRndMaxVal
  60. }
  61. // libmysql/password.c
  62. func pwHash(password []byte) (result [2]uint32) {
  63. var nr, add, nr2, tmp uint32
  64. nr, add, nr2 = 1345345333, 7, 0x12345671
  65. for _, c := range password {
  66. if c == ' ' || c == '\t' {
  67. continue // skip space in password
  68. }
  69. tmp = uint32(c)
  70. nr ^= (((nr & 63) + add) * tmp) + (nr << 8)
  71. nr2 += (nr2 << 8) ^ nr
  72. add += tmp
  73. }
  74. result[0] = nr & ((1 << 31) - 1) // Don't use sign bit (str2int)
  75. result[1] = nr2 & ((1 << 31) - 1)
  76. return
  77. }
  78. func encryptedOldPassword(password string, scramble []byte) []byte {
  79. if len(password) == 0 {
  80. return nil
  81. }
  82. scramble = scramble[:8]
  83. hashPw := pwHash([]byte(password))
  84. hashSc := pwHash(scramble)
  85. r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
  86. var out [8]byte
  87. for i := range out {
  88. out[i] = byte(math.Floor(r.Float64()*31) + 64)
  89. }
  90. extra := byte(math.Floor(r.Float64() * 31))
  91. for i := range out {
  92. out[i] ^= extra
  93. }
  94. return out[:]
  95. }