github.com/XiaoMi/Gaea@v1.2.5/mysql/util.go (about)

     1  // Copyright 2016 The kingshard Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  // Copyright 2019 The Gaea Authors. All Rights Reserved.
    16  //
    17  // Licensed under the Apache License, Version 2.0 (the "License");
    18  // you may not use this file except in compliance with the License.
    19  // You may obtain a copy of the License at
    20  //
    21  //     http://www.apache.org/licenses/LICENSE-2.0
    22  //
    23  // Unless required by applicable law or agreed to in writing, software
    24  // distributed under the License is distributed on an "AS IS" BASIS,
    25  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    26  // See the License for the specific language governing permissions and
    27  // limitations under the License.
    28  
    29  package mysql
    30  
    31  import (
    32  	"crypto/sha1"
    33  	"crypto/sha256"
    34  	"math/rand"
    35  	"time"
    36  	"unicode/utf8"
    37  )
    38  
    39  var (
    40  	dontEscape = byte(255)
    41  	encodeMap  [256]byte
    42  )
    43  
    44  // CalcPassword calculate password hash
    45  func CalcPassword(scramble, password []byte) []byte {
    46  	if len(password) == 0 {
    47  		return nil
    48  	}
    49  
    50  	// stage1Hash = SHA1(password)
    51  	crypt := sha1.New()
    52  	crypt.Write(password)
    53  	stage1 := crypt.Sum(nil)
    54  
    55  	// scrambleHash = SHA1(scramble + SHA1(stage1Hash))
    56  	// inner Hash
    57  	crypt.Reset()
    58  	crypt.Write(stage1)
    59  	hash := crypt.Sum(nil)
    60  
    61  	// outer Hash
    62  	crypt.Reset()
    63  	crypt.Write(scramble)
    64  	crypt.Write(hash)
    65  	scramble = crypt.Sum(nil)
    66  
    67  	// token = scrambleHash XOR stage1Hash
    68  	for i := range scramble {
    69  		scramble[i] ^= stage1[i]
    70  	}
    71  	return scramble
    72  }
    73  
    74  func CalcCachingSha2Password(salt []byte, password string) []byte {
    75  	if len(password) == 0 {
    76  		return nil
    77  	}
    78  	// XOR(SHA256(password), SHA256(SHA256(SHA256(password)), salt))
    79  	crypt := sha256.New()
    80  	crypt.Write([]byte(password))
    81  	message1 := crypt.Sum(nil)
    82  
    83  	crypt.Reset()
    84  	crypt.Write(message1)
    85  	message1Hash := crypt.Sum(nil)
    86  
    87  	crypt.Reset()
    88  	crypt.Write(message1Hash)
    89  	crypt.Write(salt)
    90  	message2 := crypt.Sum(nil)
    91  
    92  	for i := range message1 {
    93  		message1[i] ^= message2[i]
    94  	}
    95  
    96  	return message1
    97  }
    98  
    99  // RandomBuf return random salt, seed must be in the range of ascii
   100  func RandomBuf(size int) ([]byte, error) {
   101  	buf := make([]byte, size)
   102  	rand.Seed(time.Now().UTC().UnixNano())
   103  	min, max := 30, 127
   104  	for i := 0; i < size; i++ {
   105  		buf[i] = byte(min + rand.Intn(max-min))
   106  	}
   107  	return buf, nil
   108  }
   109  
   110  // Escape remove exceptional character
   111  func Escape(sql string) string {
   112  	dest := make([]byte, 0, 2*len(sql))
   113  
   114  	for i, w := 0, 0; i < len(sql); i += w {
   115  		runeValue, width := utf8.DecodeRuneInString(sql[i:])
   116  		if c := encodeMap[byte(runeValue)]; c == dontEscape {
   117  			dest = append(dest, sql[i:i+width]...)
   118  		} else {
   119  			dest = append(dest, '\\', c)
   120  		}
   121  		w = width
   122  	}
   123  
   124  	return string(dest)
   125  }
   126  
   127  var encodeRef = map[byte]byte{
   128  	'\x00': '0',
   129  	'\'':   '\'',
   130  	'"':    '"',
   131  	'\b':   'b',
   132  	'\n':   'n',
   133  	'\r':   'r',
   134  	'\t':   't',
   135  	26:     'Z', // ctl-Z
   136  	'\\':   '\\',
   137  }
   138  
   139  type lengthAndDecimal struct {
   140  	length  int
   141  	decimal int
   142  }
   143  
   144  // defaultLengthAndDecimal provides default Flen and Decimal for fields
   145  // from CREATE TABLE when they are unspecified.
   146  var defaultLengthAndDecimal = map[byte]lengthAndDecimal{
   147  	TypeBit:        {1, 0},
   148  	TypeTiny:       {4, 0},
   149  	TypeShort:      {6, 0},
   150  	TypeInt24:      {9, 0},
   151  	TypeLong:       {11, 0},
   152  	TypeLonglong:   {20, 0},
   153  	TypeDouble:     {22, -1},
   154  	TypeFloat:      {12, -1},
   155  	TypeNewDecimal: {11, 0},
   156  	TypeDuration:   {10, 0},
   157  	TypeDate:       {10, 0},
   158  	TypeTimestamp:  {19, 0},
   159  	TypeDatetime:   {19, 0},
   160  	TypeYear:       {4, 0},
   161  	TypeString:     {1, 0},
   162  	TypeVarchar:    {5, 0},
   163  	TypeVarString:  {5, 0},
   164  	TypeTinyBlob:   {255, 0},
   165  	TypeBlob:       {65535, 0},
   166  	TypeMediumBlob: {16777215, 0},
   167  	TypeLongBlob:   {4294967295, 0},
   168  	TypeJSON:       {4294967295, 0},
   169  	TypeNull:       {0, 0},
   170  	TypeSet:        {-1, 0},
   171  	TypeEnum:       {-1, 0},
   172  }
   173  
   174  // IsIntegerType indicate whether tp is an integer type.
   175  func IsIntegerType(tp byte) bool {
   176  	switch tp {
   177  	case TypeTiny, TypeShort, TypeInt24, TypeLong, TypeLonglong:
   178  		return true
   179  	}
   180  	return false
   181  }
   182  
   183  // GetDefaultFieldLengthAndDecimal returns the default display length (flen) and decimal length for column.
   184  // Call this when no Flen assigned in ddl.
   185  // or column value is calculated from an expression.
   186  // For example: "select count(*) from t;", the column type is int64 and Flen in ResultField will be 21.
   187  // See https://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html
   188  func GetDefaultFieldLengthAndDecimal(tp byte) (flen int, decimal int) {
   189  	val, ok := defaultLengthAndDecimal[tp]
   190  	if ok {
   191  		return val.length, val.decimal
   192  	}
   193  	return -1, -1
   194  }
   195  
   196  // defaultLengthAndDecimal provides default Flen and Decimal for fields
   197  // from CAST when they are unspecified.
   198  var defaultLengthAndDecimalForCast = map[byte]lengthAndDecimal{
   199  	TypeString:     {0, -1}, // Flen & Decimal differs.
   200  	TypeDate:       {10, 0},
   201  	TypeDatetime:   {19, 0},
   202  	TypeNewDecimal: {11, 0},
   203  	TypeDuration:   {10, 0},
   204  	TypeLonglong:   {22, 0},
   205  	TypeJSON:       {4194304, 0}, // Flen differs.
   206  }
   207  
   208  // GetDefaultFieldLengthAndDecimalForCast returns the default display length (flen) and decimal length for casted column
   209  // when flen or decimal is not specified.
   210  func GetDefaultFieldLengthAndDecimalForCast(tp byte) (flen int, decimal int) {
   211  	val, ok := defaultLengthAndDecimalForCast[tp]
   212  	if ok {
   213  		return val.length, val.decimal
   214  	}
   215  	return -1, -1
   216  }
   217  
   218  func init() {
   219  	for i := range encodeMap {
   220  		encodeMap[i] = dontEscape
   221  	}
   222  	for i := range encodeMap {
   223  		if to, ok := encodeRef[byte(i)]; ok {
   224  			encodeMap[byte(i)] = to
   225  		}
   226  	}
   227  }