Skip to content

Go SM4加解密

Go SM4加解密 - 2023·06/20 21:47 (参考链接)


go
package main

import (
  "bytes"
  "crypto/cipher"
  "encoding/hex"
  "fmt"

  "github.com/tjfoc/gmsm/sm4"
)

// SM4加密
func SM4Encrypt(data string) (result string, err error) {
  //字符串转byte切片
  plainText := []byte(data)
  //建议从配置文件中读取秘钥,进行统一管理
  SM4Key := "Uv6tkf2M3xYSRuFv"
  //todo 注意:iv需要是随机的,进一步保证加密的安全性,将iv的值和加密后的数据一起返回给外部
  SM4Iv := "04TzMuvkHm_EZnHm"
  iv := []byte(SM4Iv)
  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)
  return cipherString, nil
}

// SM4解密 传入string 输出string
func SM4Decrypt(data string) (res string, err error) {
  //秘钥
  SM4Key := "Uv6tkf2M3xYSRuFv"
  //iv是Initialization Vector,初始向量,
  SM4Iv := "04TzMuvkHm_EZnHm"
  iv := []byte(SM4Iv)
  key := []byte(SM4Key)
  block, err := sm4.NewCipher(key)
  if err != nil {
    panic(err)
  }
  //使用hex解码
  decodeString, err := hex.DecodeString(data)
  if err != nil {
    return "", err
  }
  //CBC模式 优点:具有较好的安全性,能够隐藏明文的模式和重复性。 缺点:加密过程是串行的,不适合并行处理。
  blockMode := cipher.NewCBCDecrypter(block, iv)
  //下文有详解这段代码的含义
  blockMode.CryptBlocks(decodeString, decodeString)
  //去掉明文后面的填充数据
  plainText := unPaddingLastGroup(decodeString)
  //直接返回字符串类型,方便外部调用
  return string(plainText), 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 unPaddingLastGroup(plainText []byte) []byte {
  //1.拿到切片中的最后一个字节
  length := len(plainText)
  lastChar := plainText[length-1]
  //2.将最后一个数据转换为整数
  number := int(lastChar)
  return plainText[:length-number]
}

func main() {
  //待加密的数据 模拟18位的身份证号
  plainText := "好可怜的母亲,一个女人带孩子,明明那么难,却不愿同流合污,靠自己的努力改变生活,如果不是被害,她会成功的[流泪][流泪]"
  //SM4加密
  decrypt, err := SM4Encrypt(plainText)
  if err != nil {
    return
  }
  fmt.Printf("sm4加密结果:%s\n", decrypt)

  //SM4解密
  sm4Decrypt, err := SM4Decrypt(decrypt)
  if err != nil {
    return
  }
  fmt.Printf("plainText:%s\n", sm4Decrypt)
  flag := plainText == sm4Decrypt
  fmt.Println("解密是否成功:", flag)
}