215 lines
5.9 KiB
Go
215 lines
5.9 KiB
Go
package util
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/aes"
|
||
"crypto/cipher"
|
||
"crypto/rand"
|
||
"encoding/base64"
|
||
"github.com/tjfoc/gmsm/sm4"
|
||
"io"
|
||
"log"
|
||
"qteam/app/third/dfpOpenSdk/exception"
|
||
)
|
||
|
||
func AesEncrypt(content string, reqParamEncryptKey string) (string, error) {
|
||
key := []byte(reqParamEncryptKey)
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
//填充原文
|
||
blockSize := block.BlockSize()
|
||
content = string(PKCS5Padding([]byte(content), blockSize))
|
||
//初始向量IV必须是唯一,但不需要保密
|
||
cipherText := make([]byte, blockSize+len(content))
|
||
//block大小 16
|
||
iv := cipherText[:blockSize]
|
||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
//block大小和初始向量大小一定要一致
|
||
mode := cipher.NewCBCEncrypter(block, iv)
|
||
mode.CryptBlocks(cipherText[blockSize:], []byte(content))
|
||
|
||
return string(cipherText), nil
|
||
}
|
||
|
||
func AesDecrypt(content string, reqParamEncryptKye string) (string, error) {
|
||
decodeKey, err := base64.StdEncoding.DecodeString(reqParamEncryptKye)
|
||
block, err := aes.NewCipher(decodeKey)
|
||
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
ciphertext, err := base64.StdEncoding.DecodeString(content)
|
||
|
||
iv := ciphertext[:aes.BlockSize]
|
||
|
||
ciphertext = ciphertext[aes.BlockSize:]
|
||
mode := cipher.NewCBCDecrypter(block, iv)
|
||
|
||
mode.CryptBlocks(ciphertext, ciphertext)
|
||
|
||
result := base64.StdEncoding.EncodeToString(ciphertext)
|
||
return result, nil
|
||
}
|
||
|
||
func PKCS7UnPadding(origData []byte) []byte {
|
||
length := len(origData)
|
||
unpadding := int(origData[length-1])
|
||
return origData[:(length - unpadding)]
|
||
}
|
||
|
||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||
padding := blockSize - len(ciphertext)%blockSize
|
||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||
return append(ciphertext, padtext...)
|
||
}
|
||
|
||
// Sm4Encrypt sm4加密
|
||
// content 待加密内容
|
||
// reqParamEncryptKey 对称加密密钥 base64格式
|
||
func Sm4Encrypt(content string, reqParamEncryptKey string) (string, error) {
|
||
iv := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
err := sm4.SetIV(iv)
|
||
if err != nil {
|
||
return "", exception.REQ_PARAM_ENCRYPT_ERR()
|
||
}
|
||
|
||
decodeString, err := base64.StdEncoding.DecodeString(reqParamEncryptKey)
|
||
if err != nil {
|
||
log.Println(err)
|
||
return "", exception.REQ_PARAM_ENCRYPT_ERR()
|
||
}
|
||
out, err := sm4.Sm4Cbc(decodeString, []byte(content), true)
|
||
|
||
if err != nil {
|
||
log.Println(err)
|
||
return "", exception.REQ_PARAM_ENCRYPT_ERR()
|
||
}
|
||
return base64.StdEncoding.EncodeToString(out), nil
|
||
|
||
}
|
||
|
||
// SM4加密
|
||
func SM4Encrypt(data, reqParamEncryptKey string) (result string, err error) {
|
||
//字符串转byte切片
|
||
plainText := []byte(data)
|
||
//建议从配置文件中读取秘钥,进行统一管理
|
||
SM4Key, err := base64.StdEncoding.DecodeString(reqParamEncryptKey)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
ivs := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
err = sm4.SetIV(ivs)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
iv := []byte(ivs)
|
||
key := []byte(SM4Key)
|
||
//实例化sm4加密对象
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
//明文数据填充
|
||
paddingData := paddingLastGroup(plainText, block.BlockSize())
|
||
//声明SM4的加密工作模式
|
||
blockMode := cipher.NewCBCEncrypter(block, iv)
|
||
//为填充后的数据进行加密处理
|
||
cipherText := make([]byte, len(paddingData))
|
||
//使用CryptBlocks这个核心方法,将paddingData进行加密处理,将加密处理后的值赋值到cipherText中
|
||
blockMode.CryptBlocks(cipherText, paddingData)
|
||
//加密结果使用hex转成字符串,方便外部调用
|
||
//cipherString := hex.EncodeToString(cipherText)
|
||
cipherString := base64.StdEncoding.EncodeToString(cipherText)
|
||
return cipherString, nil
|
||
}
|
||
|
||
// 明文数据填充
|
||
func paddingLastGroup(plainText []byte, blockSize int) []byte {
|
||
//1.计算最后一个分组中明文后需要填充的字节数
|
||
padNum := blockSize - len(plainText)%blockSize
|
||
//2.将字节数转换为byte类型
|
||
char := []byte{byte(padNum)}
|
||
//3.创建切片并初始化
|
||
newPlain := bytes.Repeat(char, padNum)
|
||
//4.将填充数据追加到原始数据后
|
||
newText := append(plainText, newPlain...)
|
||
return newText
|
||
}
|
||
|
||
func Sm4Decrypt(content string, reqParamEncryptKey string) (string, error) {
|
||
iv := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
err := sm4.SetIV(iv)
|
||
|
||
if err != nil {
|
||
log.Println(err)
|
||
return "", exception.REQ_PARAM_ENCRYPT_ERR()
|
||
}
|
||
|
||
decodeKey, err := base64.StdEncoding.DecodeString(reqParamEncryptKey)
|
||
decodeContent, _ := base64.StdEncoding.DecodeString(content)
|
||
out, err := sm4.Sm4Cbc(decodeKey, decodeContent, false)
|
||
|
||
if err != nil {
|
||
log.Println(err)
|
||
return "", exception.REQ_PARAM_ENCRYPT_ERR()
|
||
}
|
||
|
||
return string(out), nil
|
||
}
|
||
|
||
// SM4解密 传入string 输出string
|
||
func SM4Decrypt2(data, reqParamEncryptKey string) (res string, err error) {
|
||
//建议从配置文件中读取秘钥,进行统一管理
|
||
SM4Key, err := base64.StdEncoding.DecodeString(reqParamEncryptKey)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
ivs := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
err = sm4.SetIV(ivs)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
iv := []byte(ivs)
|
||
key := []byte(SM4Key)
|
||
//实例化sm4加密对象
|
||
block, err := sm4.NewCipher(key)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
base64Content, err := base64.StdEncoding.DecodeString(data)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
//CBC模式 优点:具有较好的安全性,能够隐藏明文的模式和重复性。 缺点:加密过程是串行的,不适合并行处理。
|
||
blockMode := cipher.NewCBCDecrypter(block, iv)
|
||
//下文有详解这段代码的含义
|
||
blockMode.CryptBlocks(base64Content, base64Content)
|
||
//去掉明文后面的填充数据
|
||
plainText := unPaddingLastGroup(base64Content)
|
||
//直接返回字符串类型,方便外部调用
|
||
return string(plainText), nil
|
||
}
|
||
|
||
// 去掉明文后面的填充数据
|
||
func unPaddingLastGroup(plainText []byte) []byte {
|
||
//1.拿到切片中的最后一个字节
|
||
length := len(plainText)
|
||
lastChar := plainText[length-1]
|
||
//2.将最后一个数据转换为整数
|
||
number := int(lastChar)
|
||
return plainText[:length-number]
|
||
}
|