美文网首页GolangGolang程序员
iGO实现之路 —— Security

iGO实现之路 —— Security

作者: ChainZhang | 来源:发表于2018-01-23 18:24 被阅读61次

    本文为转载,原文:iGO实现之路 —— Security

    Golang

    介绍

    在我们写代码的过程中,可能会遇到很多的数据安全问题。比如我们在后端进行http请求的时候,url编码问题;用户登录密码数据库的保存方案;以及一些重要数据保存等。

    这些都需要进行不同程度的编码,解码,加密解密。

    那么,这些功能在golang中该如何实现呢?

    源码

    igo-github源码地址

    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

    iGO我的go语言库

    相关文章

      网友评论

        本文标题:iGO实现之路 —— Security

        本文链接:https://www.haomeiwen.com/subject/jcqeaxtx.html