有個項目中正好須要用到一個對稱加解密函數,想起了,DZ的那個authcode函數,因而乎在網上找了哈,沒有發現,不曉得是否是我搜索技術不夠哈,總之是沒有找到,好吧,本身動手豐衣足食。。。GO。 git
大概原來是祕鑰放在加密串中的,過時時間也在裏面,而後是驗證字符串,解密的時候要先出去前面幾位的動態祕鑰,固然能夠不用哈,那麼每次加密結果都同樣的。 github
key + text 算法
text[0:10]過時時間 0:不過時 app
text[10:26]驗證字符串 函數
text[26:]原字符串 加密
// 加解密函數 根據dz的Authcode改寫的go版本 // params[0] 加密or解密 bool true:加密 false:解密 默認false // params[1] 祕鑰 // params[2] 加密:過時時間 // params[3] 動態祕鑰長度 默認:4位 不能大於32位 func Authcode(text string, params ...interface{}) string { l := len(params) isEncode := false key := "" expiry := 0 cKeyLen := 4 if l > 0 { isEncode = params[0].(bool) } if l > 1 { key = params[1].(string) } if l > 2 { expiry = params[2].(int) if expiry < 0 { expiry = 0 } } if l > 3 { cKeyLen = params[3].(int) if cKeyLen < 0 { cKeyLen = 0 } } if cKeyLen > 32 { cKeyLen = 32 } timestamp := time.Now().Unix() // md5加密key mKey := Md5Sum(key) // 參與加密的 keyA := Md5Sum(mKey[0:16]) // 用於驗證數據有效性的 keyB := Md5Sum(mKey[16:]) // 動態部分 var keyC string if cKeyLen > 0 { if isEncode { // 加密的時候,動態獲取一個祕鑰 keyC = Md5Sum(fmt.Sprint(timestamp))[32-cKeyLen:] } else { // 解密的時候從頭部獲取動態祕鑰部分 keyC = text[0:cKeyLen] } } // 加入了動態的祕鑰 cryptKey := keyA + Md5Sum(keyA+keyC) // 祕鑰長度 keyLen := len(cryptKey) if isEncode { // 加密 前10位是過時驗證字符串 10-26位字符串驗證 var d int64 if expiry > 0 { d = timestamp + int64(expiry) } text = fmt.Sprintf("%010d%s%s", d, Md5Sum(text + keyB)[0:16], text) } else { // 解密 text = string(Base64Decode(text[cKeyLen:])) } // 字符串長度 textLen := len(text) if textLen <= 0 { return "" } // 密匙簿 box := Range(0, 256) // 對稱算法 var rndKey []int cryptKeyB := []byte(cryptKey) for i := 0; i < 256; i++ { pos := i % keyLen rndKey = append(rndKey, int(cryptKeyB[pos])) } j := 0 for i := 0; i < 256; i++ { j = (j + box[i] + rndKey[i]) % 256 box[i], box[j] = box[j], box[i] } textB := []byte(text) a := 0 j = 0 var result []byte for i := 0; i < textLen; i++ { a = (a + 1) % 256 j = (j + box[a]) % 256 box[a], box[j] = box[j], box[a] result = append(result, byte(int(textB[i])^(box[(box[a]+box[j])%256]))) } if isEncode { return keyC + strings.Replace(Base64Encode(result), "=", "", -1) } // 獲取前10位,判斷過時時間 d := Atoi64(string(result[0:10]), 0) if (d == 0 || d-timestamp > 0) && string(result[10:26]) == Md5Sum(string(result[26:]) + keyB)[0:16] { return string(result[26:]) } return "" }裏面有幾個自定義的相關函數,比較簡單的,須要特別說明下得是Base64Decode這個
func Base64Decode(str string) []byte { var b []byte var err error x := len(str) * 3 % 4 switch { case x == 2: str += "==" case x == 1: str += "=" } if b, err = base64.StdEncoding.DecodeString(str); err != nil { return b } return b }
由於在加密用到Base64Encode之後,替換了=爲空字符串,因此這裏須要處理下,PHP裏面的base64_decode函數是能夠直接處理,這裏本身卡了幾個小時去研究了下BASE64得原理,base64是說3個字符轉成4個字符的方法。由於3個字符二進制恰好24位,分紅4個,那麼每一個只有6位二進制,算一下恰好64,因此base64的全部字符就是64個,從A..Za..z0..9+/恰好64個。若是當轉換中,若是少了,後面補=號,因此會出現最後一個=號和兩個=號的狀況。這裏根據這個原理反補了等號回去,由於GO自己的解碼函數沒有處理這個。 code
完整文件包,在這裏,https://github.com/last911/utils/blob/master/tools.go md5
週末了,回家了。公司好像還不少人呢。 字符串
星期天要踢球,安逸。。。回家 get