本文为转载,原文: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
网友评论