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/go-trustlog/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 }