golang加密:
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"github.com/tjfoc/gmsm/sm2"
)
func main() {
// 生成SM2密钥对
privateKey, err := sm2.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// 打印出私钥D值(注意:实际应用中不应直接打印或暴露私钥)
fmt.Printf("Private Key D: %x\n", privateKey.D.Bytes())
// 将公钥转换为04开头的X9.62格式字符串
pubKeyBytes := append([]byte{0x04}, append(privateKey.X.Bytes(), privateKey.Y.Bytes()...)...)
pubKeyStr := hex.EncodeToString(pubKeyBytes)
fmt.Printf("Public Key: %s\n", pubKeyStr)
// 准备要签名的消息
message := []byte("Hello World!")
// 使用私钥对消息进行签名
signature, err := privateKey.Sign(rand.Reader, message, nil)
if err != nil {
panic(err)
}
// 打印签名结果(通常会以Base64或Hex编码形式传输)
sigStr := hex.EncodeToString(signature)
fmt.Printf("Signature: %s\n", sigStr)
}
java解密:
import java.security.spec.*;
import java.util.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.security.Security;
import java.security.KeyFactory;
import java.security.PublicKey;
@Test
void sm2Test() throws Exception {
// 假设从Go端接收到的公钥是04开头的X9.62格式字符串
String pubKeyStr = "046ae10d888e6dfa1bda8987f69fce9cbf2b73afa8b17666593db1edabe224ecbe9214fecac1b576e65614b99cf497e45c017eb41f67cd51a8b0c315061b3028b5"; // 替换为实际接收到的公钥字符串
byte[] pubKeyBytes = Hex.decode(pubKeyStr.substring(2)); // 去掉前缀"04"
// 确保公钥字节数组长度为偶数
if (pubKeyBytes.length % 2 != 0) {
throw new IllegalArgumentException("Public key length must be even.");
}
// 分割为X坐标
byte[] xCoordBytes = Arrays.copyOfRange(pubKeyBytes, 0, pubKeyBytes.length / 2);
// 分割为Y坐标
byte[] yCoordBytes = Arrays.copyOfRange(pubKeyBytes, pubKeyBytes.length / 2, pubKeyBytes.length);
// 加载SM2曲线参数
ECNamedCurveParameterSpec sm2Params = ECNamedCurveTable.getParameterSpec("sm2p256v1");
// 构建ECParameterSpec对象
ECParameterSpec ecSpec = new ECNamedCurveSpec(
"sm2p256v1", // 曲线名称
sm2Params.getCurve(), // 椭圆曲线
sm2Params.getG(), // 基点
sm2Params.getN() // 阶数
);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
new ECPoint(new BigInteger(1, xCoordBytes),
new BigInteger(1, yCoordBytes)),
ecSpec
);
// 获取ECPublicKey实例
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
// 解码来自Go端的签名
String sigStr = "304402204c20712bb1088ed7476c24d64518cdce722c2b31ec5639aca9ed30e5676ce6ba02200d57823f08dc009e980ca2db1db9a6ecce2a5c66fefca38bc730c9382ab36580"; // 替换为实际接收到的签名字符串
byte[] signature = Hex.decode(sigStr);
// 初始化SM2签名器
SM2Signer signer = new SM2Signer();
ECDomainParameters domainParams = new ECDomainParameters(
sm2Params.getCurve(), // 椭圆曲线
sm2Params.getG(), // 基点
sm2Params.getN() // 阶数
);
// 直接从xCoordBytes和yCoordBytes构建ECPoint对象
org.bouncycastle.math.ec.ECPoint q = sm2Params.getCurve().createPoint(
new BigInteger(1, xCoordBytes),
new BigInteger(1, yCoordBytes)
);
// 使用ECPoint对象初始化ECPublicKeyParameters
ECPublicKeyParameters publicKeyParams = new ECPublicKeyParameters(q, domainParams);
// 初始化签名验证器
signer.init(false, publicKeyParams);
// 更新签名器
byte[] message = "Hello World!".getBytes(); // 确保与Go端相同的消息内容
signer.update(message, 0, message.length);
// 验证签名
boolean isValid = signer.verifySignature(signature);
System.out.println("Signature is valid: " + isValid);
}
pom.xml依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>