您的位置:首页 > 编程语言 > Go语言

go语言版本的discuz authcode函数实现

2013-11-09 17:54 573 查看
有个项目中正好需要用到一个对称加解密函数,想起了,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

周末了,回家了。公司好像还很多人呢。

星期天要踢球,安逸。。。回家
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息