国密sm4加密

国密sm4-golang使用

sm4

国密SM4算法是一种分组加密算法。SM4分组密码(block cipher)算法是一种迭代分组密码算法,由加解密算法和密钥扩展算法组成。

SM4是一种Feistel结构的分组密码算法,其分组长度和密钥长度均为128bits。加密算法和密钥扩展算法迭代轮数均为32轮。SM4加解密过程的算法相同但是轮密钥的使用顺序相反

开发

这里我们使用 gmsm库来实现国密sm4算法的加密和解密

https://github.com/emmansun/gmsm

封装代码

package sm4

import (
	"crypto/cipher"
	"encoding/base64"

	"github.com/emmansun/gmsm/sm4"
)
func Encrypt(SrcData []byte, appKey, appIv string) (string, error) {
	key, _ := base64.StdEncoding.DecodeString(appKey)
	iv, _ := base64.StdEncoding.DecodeString(appIv)
	block, _ := sm4.NewCipher(key)
	// 手动填充
	SrcData = pkcs5Padding(SrcData, 16)
	// CTR 模式加密
	stream := cipher.NewCTR(block, iv)
	ciphertext := make([]byte, len(SrcData))
	stream.XORKeyStream(ciphertext, SrcData)
	// Base64 编码加密结果
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

func Decrypt(base64Data string, appKey, appIv string) ([]byte, error) {
	key, _ := base64.StdEncoding.DecodeString(appKey)
	iv, _ := base64.StdEncoding.DecodeString(appIv)
	block, err := sm4.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// Base64 解码密文
	ciphertext, err := base64.StdEncoding.DecodeString(base64Data)
	if err != nil {
		return nil, err
	}

	// CTR 模式解密
	stream := cipher.NewCTR(block, iv)
	plaintext := make([]byte, len(ciphertext))
	stream.XORKeyStream(plaintext, ciphertext)

	// 手动去除填充
	plaintext, err = pkcs5UnPadding(plaintext)
	return plaintext, nil
}


// PKCS5Padding 填充
func pkcs5Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := make([]byte, padding)
	for i := range padText {
		padText[i] = byte(padding)
	}
	return append(data, padText...)
}

// PKCS5UnPadding 去除填充
func pkcs5UnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("解密数据为空")
	}
	paddingLen := int(data[length-1])
	if paddingLen > length || paddingLen > 16 {
		return nil, errors.New("填充长度不正确")
	}
	return data[:length-paddingLen], nil
}

func DecodeSecretKey(secret string) string {
	decodeData, _ := base64.StdEncoding.DecodeString(secret)
	return string(decodeData)
}

注意⚠️:一些平台在使用sm4的使用对外提供的appKeyappIV可能并不是事件用到的密钥,可能是随机数种子,需要你去自己二次生成

posted @ 2025-03-20 16:12  Koduck  阅读(209)  评论(0)    收藏  举报