golang使用aes加密

aes_encrypt.go

package aes_encrypt

import (
    "crypto/aes"
    "crypto/cipher"
    "fmt"
)

type paddingFunc func([]byte, int) []byte
type unPaddingFunc func([]byte) []byte


const (
    CipherModeBlock = iota
    CipherModeStream 

    PaddingTypePKCS5
    PaddingTypePKCS7
    
    EncryptTypeUseECB
    EncryptTypeUseCBC
    EncryptTypeUseCFB
    EncryptTypeUseOFB
)

type EnDecryptor struct {
    cipherMode int //
    paddingType int //
    encryptType int //
    paddingFunc paddingFunc //
    unPaddingFunc unPaddingFunc //
    cipherBlockEncryptor cipher.BlockMode
    cipherStreamEncryptor cipher.Stream
    cipherBlockDecryptor cipher.BlockMode
    cipherStreamDecryptor cipher.Stream
    blockLength int
    key []byte // 
    iv []byte //
}

func NewEnDecryptor(key []byte,iv []byte,encryptType int,paddingType int)(*EnDecryptor,error){
    edcryptor := &EnDecryptor{}
    edcryptor.key = key
    edcryptor.iv = iv
    var (
        paddingFuncFinal paddingFunc
        unPaddingFuncFinal unPaddingFunc
        cipherMode int
    )
    //设置paddingType
    edcryptor.encryptType = encryptType
    edcryptor.paddingType = paddingType

    switch paddingType {
        case PaddingTypePKCS5:
            paddingFuncFinal = PKCS5Padding
            unPaddingFuncFinal = PKCS5UnPadding
        case PaddingTypePKCS7:
            paddingFuncFinal = PKCS7Padding
            unPaddingFuncFinal = PKCS7UnPadding
        default:
            return nil,fmt.Errorf("不支持的padding_type:%v",paddingType)
    }

    edcryptor.paddingFunc = paddingFuncFinal
    edcryptor.unPaddingFunc = unPaddingFuncFinal

    switch encryptType{
    case EncryptTypeUseECB:
        cipherMode = CipherModeBlock
        block, err := aes.NewCipher(key)
        if err != nil {
            return nil,err
        }
        edcryptor.cipherMode = CipherModeBlock
        edcryptor.cipherBlockEncryptor = newECBEncrypter(block)
        edcryptor.cipherBlockDecryptor = newECBDecrypter(block)
        edcryptor.blockLength = block.BlockSize()
    case EncryptTypeUseCBC:
        edcryptor.cipherMode = CipherModeBlock
        block, err := aes.NewCipher(key)
        if err != nil {
            return nil,err
        }
        edcryptor.cipherMode = CipherModeBlock
        edcryptor.cipherBlockEncryptor = cipher.NewCBCEncrypter(block,iv)
        edcryptor.cipherBlockDecryptor = cipher.NewCBCDecrypter(block,iv)
        edcryptor.blockLength = block.BlockSize()
    case EncryptTypeUseCFB:
        edcryptor.cipherMode = CipherModeStream
        block, err := aes.NewCipher(key)
        if err != nil {
            return nil,err
        }
        edcryptor.cipherStreamEncryptor = cipher.NewCFBEncrypter(block,iv)
        edcryptor.cipherStreamDecryptor = cipher.NewCFBDecrypter(block,iv)
        edcryptor.blockLength = block.BlockSize()
    case EncryptTypeUseOFB:
        edcryptor.cipherMode = CipherModeStream
        block, err := aes.NewCipher(key)
        if err != nil {
            return nil,err
        }
        edcryptor.cipherStreamEncryptor = cipher.NewOFB(block,iv)
        edcryptor.cipherStreamDecryptor = cipher.NewOFB(block,iv)
        edcryptor.blockLength = block.BlockSize()
    default:
        return nil,fmt.Errorf("不支持的cipherMode:%v",cipherMode)
    }
    return edcryptor,nil
    
}

//加密
func (edcryptor *EnDecryptor) CommonEncrypt(origData []byte) []byte {
    //block加密
    origData = edcryptor.paddingFunc(origData,edcryptor.blockLength)
    crypted := make([]byte, len(origData))
    if edcryptor.cipherMode ==  CipherModeBlock {
        edcryptor.cipherBlockEncryptor.CryptBlocks(crypted, origData)
    } else {
        //stream加密
        edcryptor.cipherStreamEncryptor.XORKeyStream(crypted, origData)
    }
    return crypted
}

//解密
func (edcryptor *EnDecryptor) CommonDecrypt(crypted []byte) []byte {
    origData := make([]byte, len(crypted))
    //块解密
    if edcryptor.cipherMode ==  CipherModeBlock {
        edcryptor.cipherBlockDecryptor.CryptBlocks(origData, crypted)
    } else {
        //stream解密
        edcryptor.cipherStreamDecryptor.XORKeyStream(origData, crypted)
    }
    origData = edcryptor.unPaddingFunc(origData)
    return origData
}

padding.go

package aes_encrypt

import "bytes"

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 := int(origData[length-1])
    if length < unpadding {
        return []byte("unpadding error")
    }
    return origData[:(length - unpadding)]
}

//PKCS7 填充模式
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    //Repeat()函数的功能是把切片[]byte{byte(padding)}复制padding个,然后合并成新的字节切片返回
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

//填充的反向操作,删除填充字符串
func PKCS7UnPadding(origData []byte) []byte {
    //获取数据长度
    length := len(origData)
    if length == 0 {
        return nil
    } else {
        //获取填充字符串长度
        unpadding := int(origData[length-1])
        //截取切片,删除填充字节,并且返回明文
        return origData[:(length - unpadding)]
    }
}

aes_ecb.go golang官方认为ECB不安全了 默认没有实现aes的ECB加密,需要我们自己加一段代码

package aesutils

import "crypto/cipher"
type ecb struct {
    b         cipher.Block
    blockSize int
}

func newECB(b cipher.Block) *ecb {
    return &ecb{
        b:         b,
        blockSize: b.BlockSize(),
    }
}

type ecbEncrypter ecb

func newECBEncrypter(b cipher.Block) cipher.BlockMode {
    return (*ecbEncrypter)(newECB(b))
}

func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
    if len(src)%x.blockSize != 0 {
        panic("crypto/cipher: input not full blocks")
    }
    if len(dst) < len(src) {
        panic("crypto/cipher: output smaller than input")
    }
    for len(src) > 0 {
        x.b.Encrypt(dst, src[:x.blockSize])
        src = src[x.blockSize:]
        dst = dst[x.blockSize:]
    }
}

type ecbDecrypter ecb

func newECBDecrypter(b cipher.Block) cipher.BlockMode {
    return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
    if len(src)%x.blockSize != 0 {
        panic("crypto/cipher: input not full blocks")
    }
    if len(dst) < len(src) {
        panic("crypto/cipher: output smaller than input")
    }
    for len(src) > 0 {
        x.b.Decrypt(dst, src[:x.blockSize])
        src = src[x.blockSize:]
        dst = dst[x.blockSize:]
    }
}

aes_encrypt_test.go 单元测试以及压力测试

package aes_encrypt

import (
    "encoding/hex"
    "fmt"
    "os"
    "testing"

    "github.com/tj/assert"
)

var (
    secret = []byte("1234512345123451")
    originalWord []byte = []byte("123456")
    iv []byte
)

func TestEnDecryptor(t *testing.T){
    myassert := assert.New(t)
    //ecb pkcs7 128位 密码aaaaa13823943639 iv为空 输出为hex 
    cryptor,err := NewEnDecryptor(secret,iv,EncryptTypeUseECB,PaddingTypePKCS7)
    myassert.Equal(err,nil,"创建NewEnDecryptor")
    b := cryptor.CommonEncrypt(originalWord)
    bstring := hex.EncodeToString(b)
    myassert.Equal(bstring,"4a97c04a11c89908568ddff6d4f833d9","加密后数据比较")

    original := cryptor.CommonDecrypt(b)
    myassert.Equal(original,originalWord,"解密后的字节数组比较")
}

func TestEnDecryptorWithStream(t *testing.T){
    myassert := assert.New(t)
    //ecb pkcs7 128位 密码aaaaa13823943639 iv为空 输出为hex 
    cryptor,err := NewEnDecryptor(secret,[]byte("1234512345123451"),EncryptTypeUseOFB,PaddingTypePKCS5)
    myassert.Equal(err,nil,"创建NewEnDecryptor")
    b := cryptor.CommonEncrypt(originalWord)
    bstring := hex.EncodeToString(b)
    myassert.Equal(bstring,"2ae979a3f853fbb2dfb93262ab2992ae","加密后数据比较")

    original := cryptor.CommonDecrypt(b)
    myassert.Equal(original,originalWord,"解密后的字节数组比较")
}


func BenchmarkEncrypt(b *testing.B) {
    cryptor,_ := NewEnDecryptor(secret,iv,EncryptTypeUseECB,PaddingTypePKCS7)
    for i := 0; i < b.N; i++ {
        cryptor.CommonEncrypt(originalWord)
    }
}

func BenchmarkDecrypt(b *testing.B) {
    cryptor,err := NewEnDecryptor(secret,iv,EncryptTypeUseECB,PaddingTypePKCS7)
    if err != nil {
        fmt.Println(err)
        os.Exit(11)
    }
    encrypted,err  := hex.DecodeString("5d41d7915aa43c212c4105a705f63007")
    if err !=nil {
        fmt.Println(err)
        os.Exit(11)
    }
    for i := 0; i < b.N; i++ {
        cryptor.CommonDecrypt(encrypted)
    }
}


func BenchmarkEncryptWithStream(b *testing.B) {
    cryptor,_ := NewEnDecryptor(secret,[]byte("1234512345123451"),EncryptTypeUseOFB,PaddingTypePKCS5)
    for i := 0; i < b.N; i++ {
        cryptor.CommonEncrypt(originalWord)
    }
}
func BenchmarkDecryptWithStream(b *testing.B) {
    cryptor,err := NewEnDecryptor(secret,[]byte("1234512345123451"),EncryptTypeUseOFB,PaddingTypePKCS5)
    if err != nil {
        fmt.Println(err)
        os.Exit(11)
    }
    encrypted,err  := hex.DecodeString("2ae979a3f853fbb2dfb93262ab2992ae")
    if err !=nil {
        fmt.Println(err)
        os.Exit(11)
    }
    for i := 0; i < b.N; i++ {
        cryptor.CommonDecrypt(encrypted)
    }
}

单元测试以及压力测试结果


Running tool: /usr/local/go/bin/go test -timeout 30s -run ^TestEnDecryptor$ seal_project/utils/encryptutils/aesutils

ok seal_project/utils/encryptutils/aesutils


Running tool: /usr/local/go/bin/go test -timeout 30s -run ^TestEnDecryptorWithStream$ seal_project/utils/encryptutils/aesutils

ok seal_project/utils/encryptutils/aesutils


Running tool: /usr/local/go/bin/go test -benchmem -run=^-bench ^BenchmarkEncrypt seal_project/utils/encryptutils/aesutils

goos: linux
goarch: amd64
pkg: seal_project/utils/encryptutils/aesutils
cpu: Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz
BenchmarkEncrypt-4 2087600 572.4 ns/op 48 B/op 3 allocs/op
PASS
ok seal_project/utils/encryptutils/aesutils 1.793s


Running tool: /usr/local/go/bin/go test -benchmem -run=^-bench ^BenchmarkDecrypt seal_project/utils/encryptutils/aesutils

goos: linux
goarch: amd64
pkg: seal_project/utils/encryptutils/aesutils
cpu: Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz
BenchmarkDecrypt-4 5478010 233.8 ns/op 16 B/op 1 allocs/op
PASS
ok seal_project/utils/encryptutils/aesutils 1.518s


Running tool: /usr/local/go/bin/go test -benchmem -run=^-bench ^BenchmarkEncryptWithStream seal_project/utils/encryptutils/aesutils

goos: linux
goarch: amd64
pkg: seal_project/utils/encryptutils/aesutils
cpu: Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz
BenchmarkEncryptWithStream-4 2057187 580.7 ns/op 48 B/op 3 allocs/op
PASS
ok seal_project/utils/encryptutils/aesutils 1.801s


Running tool: /usr/local/go/bin/go test -benchmem -run=^-bench ^BenchmarkDecryptWithStream seal_project/utils/encryptutils/aesutils

goos: linux
goarch: amd64
pkg: seal_project/utils/encryptutils/aesutils
cpu: Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz
BenchmarkDecryptWithStream-4 3489492 339.1 ns/op 30 B/op 1 allocs/op
PASS
ok seal_project/utils/encryptutils/aesutils 1.548s

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

推荐阅读更多精彩内容