go语言版本的discuz authcode函数实现
有个项目中正好需要用到一个对称加解密函数,想起了,DZ的那个authcode函数,于是乎在网上找了哈,没有发现,不晓得是不是我搜索技术不够哈,总之是没有找到,好吧,自己动手丰衣足食。。。GO。
大概原来是秘钥放在加密串中的,过期时间也在里面,然后是验证字符串,解密的时候要先出去前面几位的动态秘钥,当然可以不用哈,那么每次加密结果都一样的。
key + text
text[0:10]过期时间 0:不过期
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本身的解码函数没有处理这个。
完整文件包,在这里,https://github.com/last911/utils/blob/master/tools.go
周末了,回家了。公司好像还很多人呢。
星期天要踢球,安逸。。。回家
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。