iGO实现之路 —— Security

本文为转载,原文: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语言库

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 148,827评论 1 317
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 63,511评论 1 266
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 99,318评论 0 218
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,108评论 0 189
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,112评论 1 266
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,387评论 1 185
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,905评论 2 283
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,657评论 0 177
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,144评论 0 223
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,744评论 2 225
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,100评论 1 236
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,565评论 2 222
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,041评论 3 216
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,769评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,301评论 0 178
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,173评论 2 239
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,313评论 2 242

推荐阅读更多精彩内容

  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 2,921评论 0 14
  • 随着对于安全度的不断要求,对于数据加解密与破解之间的斗争,加解密的方式也在不断发生着变化,来看看现在流行的一些加解...
    zhouhao_180阅读 1,995评论 1 12
  • MD5:MD5(Message Digest Algorithm 5,消息摘要算法第五版)可以把一个任意长度的字节...
    Fsn_soul阅读 2,604评论 0 2
  • 洛桑陀美上师:《和谐中的智慧》—【每天学会感恩】(一) 作为一个出家人,我时常提醒自己要感恩。感谢上师恩,特别是我...
    祥云_17ec阅读 155评论 0 0
  • 前言 我从小就比较招女孩,整个大院的小姑娘都爱跟我玩,虽然我自己并不知道为什么。或许你会觉得自带"天然撩妹技能而不...
    蓝海呦阅读 222评论 0 0