📌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随机填充
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"
"errors"
)
// Cipher 一处实例化后可以多处并发安全复用
type Cipher struct {
block cipher.Block
iv []byte
}
func NewDesCipher(key, iv []byte) (*Cipher, error) {
return newCipher(des.NewCipher, key, iv)
}
func NewTripleDesCipher(key, iv []byte) (*Cipher, error) {
return newCipher(des.NewTripleDESCipher, key, iv)
}
func NewAesCipher(key, iv []byte) (*Cipher, error) {
return newCipher(aes.NewCipher, key, iv)
}
func newCipher(f func([]byte) (cipher.Block, error), key, iv []byte) (*Cipher, error) {
block, err := f(key)
if err != nil {
return nil, err
}
ivb := make([]byte, block.BlockSize())
copy(ivb, iv)
return &Cipher{
block: block,
iv: 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...)
}
var ErrInvalidPadLen = errors.New("invalid padding length")
// 三种填充方式去除填充的方法都相同,根据最后一位来精确定位截取长度
func trimPadding(dst []byte) ([]byte, error) {
length := len(dst)
if length == 0 {
return dst, nil
}
pad := int(dst[length-1])
if length < pad {
return nil, ErrInvalidPadLen
}
return dst[:length-pad], nil
}
func (c *Cipher) EncryptECB(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 *Cipher) DecryptECB(s string) ([]byte, error) {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
bs := c.block.BlockSize()
length := len(src)
if length%bs != 0 {
return nil, ErrInvalidPadLen
}
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 *Cipher) EncryptCBC(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 *Cipher) DecryptCBC(s string) ([]byte, error) {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
dst := make([]byte, len(src))
bm := cipher.NewCBCDecrypter(c.block, c.iv)
bm.CryptBlocks(dst, src)
return trimPadding(dst)
}
func (c *Cipher) EncryptCFB(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 *Cipher) DecryptCFB(s string) ([]byte, error) {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
dst := make([]byte, len(src))
stream := cipher.NewCFBDecrypter(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst, nil
}
func (c *Cipher) EncryptOFB(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 *Cipher) DecryptOFB(s string) ([]byte, error) {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
dst := make([]byte, len(src))
stream := cipher.NewOFB(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst, nil
}
func (c *Cipher) EncryptCTR(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 *Cipher) DecryptCTR(s string) ([]byte, error) {
src, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
dst := make([]byte, len(src))
stream := cipher.NewCTR(c.block, c.iv)
stream.XORKeyStream(dst, src)
return dst, nil
}