Golang📌应用📌加密算法📌2-ades.txt
"crypto/cipher"包提供了不同工作模式的核心算法,加解密得到密文或明文的字节数组。
密钥、明文、密文的字节数组通常使用Base64Std编码,也可以使用其他字节编码方式。
两种明文块填充方式的实现:
func Padding(src []byte, blockSize int) []byte {
length := len(src)
pad := blockSize - length%blockSize
padText := make([]byte, pad-1) // * AnsiX923补零填充
//rand.Read(padText) // * Iso10126随机填充
padText = append(padText, byte(pad))
res := make([]byte, length, length+pad)
copy(res, src)
return append(res, padText...)
}
五种工作模式比较:
密文长度:ECB=CBC>CFB=OFB=CTR
内存占用:ECB<CFB<CBC<OFB=CTR
加密耗时:ECB<CFB<CBC<CTR<OFB
建议:性能要求更高的场景(eg:日志实时加密)选用ECB/CFB模式,安全性要求更高的场景(eg:落库数据)选用CTR模式。
DES,3DES,AES有相似的初始化方法,相同的5种工作模式,可统一封装成通用方法。
DES密钥8字节,向量8字节。3DES密钥24字节,向量8字节。AES密钥16/24/32字节,向量16字节。
密文的编码方式通常采用标准的base64,但在某些场景也可以使用其他编码方式(hex,base64url等)。
========== ========== ========== ========== ==========
package ades
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
)
type Cipher interface {
Encrypt(src []byte) string
Decrypt(s string) []byte
}
type (
param struct {
block cipher.Block
iv []byte
}
ecb param
cbc param
cfb param
ofb param
ctr param
)
func NewDesECB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewCipher, key, iv)
return ecb{block, ivb}, err
}
func NewDesCBC(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewCipher, key, iv)
return cbc{block, ivb}, err
}
func NewDesCFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewCipher, key, iv)
return cfb{block, ivb}, err
}
func NewDesOFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewCipher, key, iv)
return ofb{block, ivb}, err
}
func NewDesCTR(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewCipher, key, iv)
return ctr{block, ivb}, err
}
func NewTripleDESCipherECB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewTripleDESCipher, key, iv)
return ecb{block, ivb}, err
}
func NewTripleDESCipherCBC(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewTripleDESCipher, key, iv)
return cbc{block, ivb}, err
}
func NewTripleDESCipherCFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewTripleDESCipher, key, iv)
return cfb{block, ivb}, err
}
func NewTripleDESCipherOFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewTripleDESCipher, key, iv)
return ofb{block, ivb}, err
}
func NewTripleDESCipherCTR(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(des.NewTripleDESCipher, key, iv)
return ctr{block, ivb}, err
}
func NewAesECB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(aes.NewCipher, key, iv)
return ecb{block, ivb}, err
}
func NewAesCBC(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(aes.NewCipher, key, iv)
return cbc{block, ivb}, err
}
func NewAesCFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(aes.NewCipher, key, iv)
return cfb{block, ivb}, err
}
func NewAesOFB(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(aes.NewCipher, key, iv)
return ofb{block, ivb}, err
}
func NewAesCTR(key, iv []byte) (Cipher, error) {
block, ivb, err := newParam(aes.NewCipher, key, iv)
return ctr{block, ivb}, err
}
func newParam(f func([]byte) (cipher.Block, error), key, iv []byte) (cipher.Block, []byte, error) {
block, err := f(key)
if err != nil {
return nil, nil, err
}
ivb := make([]byte, block.BlockSize())
copy(ivb, iv)
return block, ivb, nil
}
func pkcs7Padding(src []byte, blockSize int) []byte {
length := len(src)
pad := blockSize - length%blockSize
padText := bytes.Repeat([]byte{byte(pad)}, pad)
res := make([]byte, length, length+pad)
copy(res, src) //复制一份防止当src后cap足够的时候append修改其后的内容
return append(res, padText...)
}
func trimPadding(dst []byte) []byte {
length := len(dst)
if length == 0 {
return dst
}
pad := int(dst[length-1])
if length < pad {
return nil
}
return dst[:length-pad]
}
func (c ecb) Encrypt(src []byte) string {
bs := c.block.BlockSize()
src = pkcs7Padding(src, bs)
length := len(src)
dst := make([]byte, length)
for i := 0; i < length; i += bs {
c.block.Encrypt(dst[i:i+bs], src[i:i+bs])
}
return base64.StdEncoding.EncodeToString(dst)
}
func (c ecb) Decrypt(s string) []byte {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil
}
bs := c.block.BlockSize()
length := len(src)
if length%bs != 0 {
return nil
}
dst := make([]byte, length)
for i := 0; i < length; i += bs {
c.block.Decrypt(dst[i:i+bs], src[i:i+bs])
}
return trimPadding(dst)
}
func (c cbc) Encrypt(src []byte) string {
src = pkcs7Padding(src, c.block.BlockSize())
dst := make([]byte, len(src))
bm := cipher.NewCBCEncrypter(c.block, c.iv)
bm.CryptBlocks(dst, src)
return base64.StdEncoding.EncodeToString(dst)
}
func (c cbc) Decrypt(s string) []byte {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil
}
dst := make([]byte, len(src))
bm := cipher.NewCBCDecrypter(c.block, c.iv)
bm.CryptBlocks(dst, src)
return trimPadding(dst)
}
func (c cfb) Encrypt(src []byte) string {
dst := make([]byte, len(src))
stream := cipher.NewCFBEncrypter(c.block, c.iv)
stream.XORKeyStream(dst, src)
return base64.StdEncoding.EncodeToString(dst)
}
func (c cfb) Decrypt(s string) []byte {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil
}
dst := make([]byte, len(src))
stream := cipher.NewCFBDecrypter(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst
}
func (c ofb) Encrypt(src []byte) string {
dst := make([]byte, len(src))
stream := cipher.NewOFB(c.block, c.iv)
stream.XORKeyStream(dst, src)
return base64.StdEncoding.EncodeToString(dst)
}
func (c ofb) Decrypt(s string) []byte {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil
}
dst := make([]byte, len(src))
stream := cipher.NewOFB(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst
}
func (c ctr) Encrypt(src []byte) string {
dst := make([]byte, len(src))
stream := cipher.NewCTR(c.block, c.iv)
stream.XORKeyStream(dst, src)
return base64.StdEncoding.EncodeToString(dst)
}
func (c ctr) Decrypt(s string) []byte {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil
}
dst := make([]byte, len(src))
stream := cipher.NewCTR(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst
}