本文为转载,原文:iGO实现之路 —— Security
Golang
介绍
在我们写代码的过程中,可能会遇到很多的数据安全问题。比如我们在后端进行http请求的时候,url编码问题;用户登录密码数据库的保存方案;以及一些重要数据保存等。
这些都需要进行不同程度的编码,解码,加密解密。
那么,这些功能在golang中该如何实现呢?
源码
base64
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
base64的编码解码,在golang的官方包里已经有了很好的支持,这里为了统一,也进行了一些简单的封装。
base64编码
/* * base64编码 */func Base64Encode(source string)string{ buf := []byte(source) return base64.StdEncoding.EncodeToString(buf) }
base64解码
/* * base64解码 */func Base64Decode(source string) (string, error){ buf, err := base64.StdEncoding.DecodeString(source) if err != nil{ return "", err } return string(buf), nil }
Url
因为url对字符是由限制的,一些特殊字符是不能出现先url里面的,比如:@
,$
,!
,#
等。所以,在进行http请求的时候,我们需要对其进行url编码,在处理请求的时候也需要相应的url解码
url编码
/* * Url编码 */func UrlEncode(source string)string{ return url.QueryEscape(source) }
url解码
/* * Url解码 */func UrlDecode(source string) (string, error){ return url.QueryUnescape(source) }
md5
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。
一般情况下,我们在保存用户密码的时候,都是将用户定义的密码通过md5加密得到的密文保存到数据库的。
当然了,在golang中对于md5的加密也是非常简单的:
/* * md5加密 */func Md5(source string, isUpper bool)string{ buf := []byte(source) has := md5.Sum(buf) md5Str := fmt.Sprintf("%x", has) if isUpper{ md5Str = strings.ToUpper(md5Str) } return md5Str}
des
DES(Data Encryption Standard)是对称加密算法,也就是加密和解密用相同的密钥。其入口参数有三个:key、data、mode。key为加密解密使用的密钥,data为加密解密的数据,mode为其工作模式。当模式为加密模式时,明文按照64位进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。实际运用中,密钥只用到了64位中的56位,这样才具有高的安全性。DES 的常见变体是三重 DES,使用 168 位的密钥对资料进行三次加密的一种机制;它通常(但非始终)提供极其强大的安全性。如果三个 56 位的子元素都相同,则三重 DES 向后兼容 DES。
des加密
/* * DES加密,CBC模式,pkcs5padding,初始向量用key填充 */func DesEncrypt(origData, key string)(string, error){ origBytes := []byte(origData) keyBytes := getDESKey(key) block, err := des.NewCipher(keyBytes) if err != nil{ return "", err } origBytes = pkcs5Padding(origBytes, block.BlockSize()) blockMode := cipher.NewCBCEncrypter(block, keyBytes) crypted := make([]byte, len(origBytes)) blockMode.CryptBlocks(crypted, origBytes) return Base64Encode(string(crypted)), nil }
des解密
/* * DES解密,CBC模式,pkcs5padding,初始向量用key填充 */func DesDecrypt(crypted, key string)(string, error){ crypted, _ = Base64Decode(crypted) cryptByts := []byte(crypted) keyByts := getDESKey(key) block, err := des.NewCipher(keyByts) if err != nil{ return "", err } blockMode := cipher.NewCBCDecrypter(block, keyByts) origByts := make([]byte, len(cryptByts)) blockMode.CryptBlocks(origByts, cryptByts) origByts = pkcs5UnPadding(origByts) return string(origByts), nil }
注意:des加密解密的秘钥长度必须为8
三重des加密
/* * 三重DES加密,CBC模式,pkcs5padding,初始向量用key填充 */func TripleDesEncrypt(origData, key string)(string, error){ origBytes := []byte(origData) keyBytes := getTripleDESKey(key) block, err := des.NewTripleDESCipher(keyBytes) if err != nil{ return "", err } origBytes = pkcs5Padding(origBytes, block.BlockSize()) blockMode := cipher.NewCBCEncrypter(block, keyBytes[:8]) crypted := make([]byte, len(origBytes)) blockMode.CryptBlocks(crypted, origBytes) return Base64Encode(string(crypted)), nil }
三重des解密
/* * 三重DES解密,CBC模式,pkcs5padding,初始向量用key填充 */func TripleDesDecrypt(crypted, key string)(string, error){ crypted, _ = Base64Decode(crypted) cryptByts := []byte(crypted) keyByts := getTripleDESKey(key) block, err := des.NewTripleDESCipher(keyByts) if err != nil{ return "", err } blockMode := cipher.NewCBCDecrypter(block, keyByts[:8]) origByts := make([]byte, len(cryptByts)) blockMode.CryptBlocks(origByts, cryptByts) origByts = pkcs5UnPadding(origByts) return string(origByts), nil }
注意:三重des加密解密的秘钥长度必须为24
aes
AES加密与DES加密一样,都是对称加密。但是相对来说,AES加密比DES更加安全,更加效率,更加灵活。
实现的话,也与DES类似。
aes加密
/* * AES加密,CBC模式,pkcs5padding,初始向量用key填充 */func AesCBCEncrypte(origData, key string) (string, error) { origByts := []byte(origData) keybytes := getAESKey(key) plaintext := pkcs5Padding(origByts, aes.BlockSize) block, err := aes.NewCipher(keybytes[:aes.BlockSize]) if err != nil{ return "", err } mode := cipher.NewCBCEncrypter(block, keybytes[:aes.BlockSize]) crypted := make([]byte, len(plaintext)) mode.CryptBlocks(crypted, plaintext) return Base64Encode(string(crypted)), nil }
aes解密
/* * AES解密,CBC模式,pkcs5padding,初始向量用key填充 */func AesCBCDecrypte(crypted string, key string) (string, error) { defer func() { if err := recover(); err != nil { fmt.Fprintf(os.Stderr, "error string:%s key:%s err:%v\n", crypted, key, err) } }() keybytes := getAESKey(key) crypted, err := Base64Decode(crypted) if err != nil { return "", errors.New("crypted data format error") } cryptedData := []byte(crypted) block, err := aes.NewCipher(keybytes[:aes.BlockSize]) if err != nil{ return "", err } mode := cipher.NewCBCDecrypter(block, keybytes[:aes.BlockSize]) decryptedData := make([]byte, len(cryptedData)) mode.CryptBlocks(decryptedData, cryptedData) cryptedData = pkcs5UnPadding(decryptedData) return strings.TrimSpace(string(decryptedData)), nil }
注意:aes的秘钥长度可以是32,24,16。
从des和aes的加密中,我们可以看到有几个自己定义的函数,比如获取key的,和pkcs5padding以及pkcs5unpadding。
下面看下这几个函数的实现
func pkcs5Padding(ciphertext []byte, blockSize int)[]byte{ padding := blockSize - len(ciphertext) % blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) }func pkcs5UnPadding(origData []byte) []byte { length := len(origData) // 去掉最后一个字节 unpadding 次 unpadding := int(origData[length-1]) return origData[:(length - unpadding)] }func getDESKey(key string)[]byte{ key = Md5(key, false) keyBytes := []byte(key) return keyBytes[0:8] }func getTripleDESKey(key string)[]byte{ key = Md5(key, false) keyBytes := []byte(key) return keyBytes[0:24] }func getAESKey(key string) []byte { key = Md5(key, false) keyLen := len(key) arrKey := []byte(key) if keyLen >= 32 { return arrKey[:32] } if keyLen >= 24 { return arrKey[:24] } return arrKey[:16] }
测试
完成了这些加解密的算法之后,再测试一下吧:
package test import( "fmt" "igo/util") func Security_test(){ source := "123456 " fmt.Println("md5 encode:", util.Md5(source, false)) base64Str := util.Base64Encode(source) fmt.Println("base 64 encode: ", base64Str) base64DecodeStr, err := util.Base64Decode(base64Str) if err == nil{ fmt.Println("base 64 decode: ", base64DecodeStr) } url := "http:www.baidu.com/s?wd=中国" urlEncode := util.UrlEncode(url) fmt.Println("url encode: ", urlEncode) urlDecode, err := util.UrlDecode(urlEncode) if err == nil{ fmt.Println("url decode: ", urlDecode) } origData := "123456" key := "11" crypted, err := util.DesEncrypt(origData, key) if err != nil{ fmt.Println("des encrypt error: ", err) }else{ fmt.Println("des encrypt: ", crypted) } decrypted, err := util.DesDecrypt(crypted, key) if err != nil{ fmt.Println("des decrypt error: ", err) }else{ fmt.Println("des decrypt: ", decrypted) } crypted, err = util.TripleDesEncrypt(origData, key) if err != nil{ fmt.Println("des encrypt error: ", err) }else{ fmt.Println("triple des encrypt: ", crypted) } decrypted, err = util.TripleDesDecrypt(crypted, key) if err != nil{ fmt.Println("triple des decrypt error: ", err) }else{ fmt.Println("triple des decrypt: ", decrypted) } crypted, err = util.AesCBCEncrypte(origData, key) if err != nil{ fmt.Println("aes error: ", err) }else{ fmt.Println("aes encrypt: ", crypted) } decrypted, err = util.AesCBCDecrypte(crypted, key) if err != nil{ fmt.Println("aes decrypt error: ", err) }else{ fmt.Println("aes decrypt: ", decrypted) } }
结果:
运行结果
完
转载请注明出处:
iGO实现之路 —— Security