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=^ 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=^ 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=^ 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=^ 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