Files
go-trustlog/api/model/signature.go
ryan d313449c5c refactor: 重构trustlog-sdk目录结构到trustlog/go-trustlog
- 将所有trustlog-sdk文件移动到trustlog/go-trustlog/目录
- 更新README中所有import路径从trustlog-sdk改为go-trustlog
- 更新cookiecutter配置文件中的项目名称
- 更新根目录.lefthook.yml以引用新位置的配置
- 添加go.sum文件到版本控制
- 删除过时的示例文件

这次重构与trustlog-server保持一致的目录结构,
为未来支持多语言SDK(Python、Java等)预留空间。
2025-12-22 13:37:57 +08:00

394 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"crypto/rand"
"errors"
"fmt"
"github.com/crpt/go-crpt"
_ "github.com/crpt/go-crpt/sm2" // Import SM2 to register it
"go.yandata.net/iod/iod/trustlog-sdk/api/logger"
)
var (
ErrPrivateKeyIsNil = errors.New("private key is nil")
ErrPublicAndKeysNotMatch = errors.New("public and private keys don't match")
)
// ComputeSignature 计算SM2签名.
// 这是 SDK 默认的签名函数,使用 SM2 算法(内部自动使用 SM3 哈希)。
//
// 参数:
// - data: 待签名的原始数据
// - privateKeyDER: 私钥的DER编码字节数组
//
// 返回: 签名字节数组.
// 注意: go-crpt 库会自动使用 SM3 算法计算摘要并签名。
func ComputeSignature(data, privateKeyDER []byte) ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Computing SM2 signature",
"dataLength", len(data),
"privateKeyDERLength", len(privateKeyDER),
)
if len(privateKeyDER) == 0 {
log.Error("Private key is empty")
return nil, errors.New("private key cannot be empty")
}
if len(data) == 0 {
log.Error("Data to sign is empty")
return nil, errors.New("data to sign cannot be empty")
}
// 解析DER格式的私钥
log.Debug("Parsing SM2 private key from DER format")
privateKey, err := crpt.PrivateKeyFromBytes(crpt.SM2, privateKeyDER)
if err != nil {
log.Error("Failed to parse SM2 private key",
"error", err,
"keyLength", len(privateKeyDER),
)
return nil, fmt.Errorf("failed to parse SM2 private key (key length: %d): %w", len(privateKeyDER), err)
}
if privateKey == nil {
log.Error("Parsed private key is nil")
return nil, ErrPrivateKeyIsNil
}
// 使用SM2签名ASN.1编码go-crpt 库会自动使用 SM3 计算摘要
log.Debug("Signing raw data with SM2 using ASN.1 encoding (SM3 hash)")
signature, err := crpt.SignMessage(privateKey, data, rand.Reader, nil)
if err != nil {
log.Error("Failed to sign data with SM2",
"error", err,
"dataLength", len(data),
)
return nil, fmt.Errorf("failed to sign data with SM2 (data length: %d): %w", len(data), err)
}
log.Debug("SM2 signature computed successfully",
"dataLength", len(data),
"signatureLength", len(signature),
)
return signature, nil
}
// VerifySignature 验证SM2签名.
// 这是 SDK 默认的验签函数,使用 SM2 算法(内部自动使用 SM3 哈希)。
//
// 参数:
// - data: 原始数据
// - publicKeyDER: 公钥的DER编码字节数组
// - signature: 签名字节数组
//
// 返回: 验证是否成功和可能的错误.
// 注意: go-crpt 库会自动使用 SM3 算法计算摘要并验证。
func VerifySignature(data, publicKeyDER, signature []byte) (bool, error) {
log := logger.GetGlobalLogger()
log.Debug("Verifying SM2 signature",
"dataLength", len(data),
"publicKeyDERLength", len(publicKeyDER),
"signatureLength", len(signature),
)
if len(publicKeyDER) == 0 {
log.Error("Public key is empty")
return false, errors.New("public key cannot be empty")
}
if len(data) == 0 {
log.Error("Data to verify is empty")
return false, errors.New("data to verify cannot be empty")
}
if len(signature) == 0 {
log.Error("Signature is empty")
return false, errors.New("signature cannot be empty")
}
// 解析DER格式的公钥,复用ParseSM2PublicDER以避免代码重复
log.Debug("Parsing SM2 public key from DER format")
publicKey, err := ParseSM2PublicDER(publicKeyDER)
if err != nil {
log.Error("Failed to parse SM2 public key",
"error", err,
"keyLength", len(publicKeyDER),
)
return false, fmt.Errorf("failed to parse SM2 public key (key length: %d): %w", len(publicKeyDER), err)
}
// 验证签名ASN.1编码go-crpt 库会自动使用 SM3 计算摘要
log.Debug("Verifying signature with SM2 using ASN.1 encoding (SM3 hash)")
ok, err := crpt.VerifyMessage(publicKey, data, crpt.Signature(signature), nil)
if err != nil {
log.Error("Failed to verify SM2 signature",
"error", err,
"dataLength", len(data),
"signatureLength", len(signature),
)
return false, fmt.Errorf("failed to verify signature: %w", err)
}
if !ok {
log.Warn("SM2 signature verification failed",
"dataLength", len(data),
"signatureLength", len(signature),
)
return false, fmt.Errorf(
"signature verification failed (data length: %d, signature length: %d)",
len(data), len(signature),
)
}
log.Debug("SM2 signature verified successfully",
"dataLength", len(data),
)
return true, nil
}
// GenerateSM2KeyPair 生成SM2密钥对.
// 这是 SDK 默认推荐的密钥生成方法。
//
// 返回新生成的密钥对,包含公钥和私钥.
// SM2 算法会在签名时自动使用 SM3 哈希。
func GenerateSM2KeyPair() (*SM2KeyPair, error) {
log := logger.GetGlobalLogger()
log.Debug("Generating SM2 key pair")
pub, priv, err := crpt.GenerateKey(crpt.SM2, rand.Reader)
if err != nil {
log.Error("Failed to generate SM2 key pair", "error", err)
return nil, fmt.Errorf("failed to generate SM2 key pair: %w", err)
}
if priv == nil {
log.Error("Generated private key is nil")
return nil, errors.New("generated private key is nil")
}
log.Debug("SM2 key pair generated successfully")
return &SM2KeyPair{
Public: pub,
Private: priv,
}, nil
}
// SM2KeyPair SM2密钥对,包含公钥和私钥.
type SM2KeyPair struct {
Public crpt.PublicKey `json:"publicKey"`
Private crpt.PrivateKey `json:"privateKey"`
}
// MarshalSM2PrivateDER 将私钥编码为DER格式.
// 将SM2私钥转换为DER格式的字节数组,用于存储或传输.
func MarshalSM2PrivateDER(priv crpt.PrivateKey) ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Marshaling SM2 private key to DER format")
if priv == nil {
log.Error("Private key is nil")
return nil, errors.New("private key is nil")
}
der := priv.Bytes()
log.Debug("SM2 private key marshaled to DER successfully",
"derLength", len(der),
)
return der, nil
}
// ParseSM2PrivateDER 从DER格式解析私钥.
// 将DER格式的字节数组解析为SM2私钥对象.
func ParseSM2PrivateDER(der []byte) (crpt.PrivateKey, error) {
log := logger.GetGlobalLogger()
log.Debug("Parsing SM2 private key from DER format",
"derLength", len(der),
)
if len(der) == 0 {
log.Error("DER encoded private key is empty")
return nil, errors.New("DER encoded private key cannot be empty")
}
key, err := crpt.PrivateKeyFromBytes(crpt.SM2, der)
if err != nil {
log.Error("Failed to parse SM2 private key from DER",
"error", err,
"derLength", len(der),
)
return nil, fmt.Errorf("failed to parse SM2 private key from DER (length: %d): %w", len(der), err)
}
log.Debug("SM2 private key parsed from DER successfully")
return key, nil
}
// MarshalSM2PublicDER 将公钥编码为DER格式.
// 将SM2公钥转换为DER格式的字节数组,用于存储或传输.
func MarshalSM2PublicDER(pub crpt.PublicKey) ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Marshaling SM2 public key to DER format")
if pub == nil {
log.Error("Public key is nil")
return nil, errors.New("public key is nil")
}
der := pub.Bytes()
log.Debug("SM2 public key marshaled to DER successfully",
"derLength", len(der),
)
return der, nil
}
// ParseSM2PublicDER 从DER格式解析公钥.
// 将DER格式的字节数组解析为SM2公钥对象.
// 返回解析后的公钥,如果数据不是有效的SM2公钥则返回错误.
func ParseSM2PublicDER(der []byte) (crpt.PublicKey, error) {
log := logger.GetGlobalLogger()
log.Debug("Parsing SM2 public key from DER format",
"derLength", len(der),
)
if len(der) == 0 {
log.Error("DER encoded public key is empty")
return nil, errors.New("DER encoded public key cannot be empty")
}
publicKey, err := crpt.PublicKeyFromBytes(crpt.SM2, der)
if err != nil {
log.Error("Failed to parse SM2 public key",
"error", err,
"derLength", len(der),
)
return nil, fmt.Errorf("failed to parse SM2 public key (DER length: %d): %w", len(der), err)
}
log.Debug("SM2 public key parsed from DER successfully")
return publicKey, nil
}
// SignMessage 使用密钥对签名消息标准SM2签名.
// 使用标准SM2算法对消息进行签名,不包含用户标识(uid).
func (kp *SM2KeyPair) SignMessage(msg []byte) ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Signing message with SM2 key pair",
"messageLength", len(msg),
)
if kp.Private == nil {
log.Error("Private key is nil")
return nil, ErrPrivateKeyIsNil
}
signature, err := crpt.SignMessage(kp.Private, msg, rand.Reader, nil)
if err != nil {
log.Error("Failed to sign message with SM2",
"error", err,
"messageLength", len(msg),
)
return nil, err
}
log.Debug("Message signed successfully with SM2",
"messageLength", len(msg),
"signatureLength", len(signature),
)
return signature, nil
}
// SignGM 使用密钥对签名消息国密标准SM2签名,带uid.
// 使用符合GB/T 32918标准的SM2算法对消息进行签名,包含用户标识(uid).
// uid用于Z值计算,通常为用户ID或标识符.
func (kp *SM2KeyPair) SignGM(msg, uid []byte) ([]byte, error) {
log := logger.GetGlobalLogger()
log.Debug("Signing message with SM2 GM standard",
"messageLength", len(msg),
"uidLength", len(uid),
)
if kp.Private == nil {
log.Error("Private key is nil")
return nil, ErrPrivateKeyIsNil
}
// go-crpt uses SM3 hash internally, pass nil for standard signing
signature, err := crpt.SignMessage(kp.Private, msg, rand.Reader, nil)
if err != nil {
log.Error("Failed to sign message with SM2 GM standard",
"error", err,
"messageLength", len(msg),
)
return nil, err
}
log.Debug("Message signed successfully with SM2 GM standard",
"messageLength", len(msg),
"signatureLength", len(signature),
)
return signature, nil
}
// VerifyMessage 使用公钥验证签名标准SM2验签.
// 验证标准SM2签名,不使用用户标识(uid).
// 返回验证结果和可能的错误.如果验证失败但没有错误发生,返回(false, nil).
func (kp *SM2KeyPair) VerifyMessage(msg, sig []byte) (bool, error) {
log := logger.GetGlobalLogger()
log.Debug("Verifying message signature with SM2",
"messageLength", len(msg),
"signatureLength", len(sig),
)
if kp.Public == nil {
log.Error("Public key is nil")
return false, ErrPublicAndKeysNotMatch
}
ok, err := crpt.VerifyMessage(kp.Public, msg, crpt.Signature(sig), nil)
if err != nil {
log.Error("Error verifying message with SM2",
"error", err,
"messageLength", len(msg),
)
return false, err
}
if ok {
log.Debug("Message signature verified successfully with SM2",
"messageLength", len(msg),
)
} else {
log.Warn("Message signature verification failed with SM2",
"messageLength", len(msg),
"signatureLength", len(sig),
)
}
return ok, nil
}
// VerifyGM 使用公钥验证签名国密标准SM2验签,带uid.
// 验证符合GB/T 32918标准的SM2签名,使用用户标识(uid).
// 返回验证结果和可能的错误.如果验证失败但没有错误发生,返回(false, nil).
func (kp *SM2KeyPair) VerifyGM(msg, sig, uid []byte) (bool, error) {
log := logger.GetGlobalLogger()
log.Debug("Verifying message signature with SM2 GM standard",
"messageLength", len(msg),
"signatureLength", len(sig),
"uidLength", len(uid),
)
if kp.Public == nil {
log.Error("Public key is nil")
return false, ErrPublicAndKeysNotMatch
}
// go-crpt uses SM3 hash internally
ok, err := crpt.VerifyMessage(kp.Public, msg, crpt.Signature(sig), nil)
if err != nil {
log.Error("Error verifying message with SM2 GM standard",
"error", err,
"messageLength", len(msg),
)
return false, err
}
if ok {
log.Debug("Message signature verified successfully with SM2 GM standard",
"messageLength", len(msg),
)
} else {
log.Warn("Message signature verification failed with SM2 GM standard",
"messageLength", len(msg),
"signatureLength", len(sig),
)
}
return ok, nil
}