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] }