From 45f42e5683a0927cf41fd2e28cb5f39856e4adf6 Mon Sep 17 00:00:00 2001 From: cheney Date: Thu, 30 Apr 2026 10:50:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=88=E8=B0=83=E8=AF=95=E8=A3=B8=E7=AD=BE?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crypto/pcie/jna/EccRefPublicKey.java | 59 +++++++++++++++++ .../openapi/service/impl/OpenApiService.java | 64 +++++++------------ 2 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/EccRefPublicKey.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/EccRefPublicKey.java index 39615d5..c745d3b 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/EccRefPublicKey.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/EccRefPublicKey.java @@ -1,6 +1,16 @@ package com.cisd.tms.integration.crypto.pcie.jna; import com.sun.jna.Structure; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; + +import java.security.PublicKey; +import java.security.Security; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.util.Arrays; import java.util.List; @Structure.FieldOrder({"bits", "x", "y"}) @@ -17,4 +27,53 @@ public class EccRefPublicKey extends Structure { protected List getFieldOrder() { return List.of("bits", "x", "y"); } + + public static EccRefPublicKey fromPublicKey(PublicKey publicKey) { + try { + if (Security.getProvider("BC") == null) { + Security.addProvider(new BouncyCastleProvider()); + } + + ECNamedCurveParameterSpec bcSpec = ECNamedCurveTable.getParameterSpec("sm2p256v1"); + ECNamedCurveSpec spec = new ECNamedCurveSpec("sm2p256v1", bcSpec.getCurve(), bcSpec.getG(), bcSpec.getN()); + + ECPoint w = ((java.security.interfaces.ECPublicKey) publicKey).getW(); + + EccRefPublicKey result = new EccRefPublicKey(); + result.bits = 256; + + byte[] xBytes = w.getAffineX().toByteArray(); + byte[] yBytes = w.getAffineY().toByteArray(); + + // 填充 x 坐标 + int xOffset = result.x.length - xBytes.length; + if (xOffset >= 0) { + System.arraycopy(xBytes, 0, result.x, xOffset, xBytes.length); + } else { + // 如果字节太长,去掉前面的0 + int start = 0; + while (start < xBytes.length && xBytes[start] == 0) { + start++; + } + System.arraycopy(xBytes, start, result.x, result.x.length - (xBytes.length - start), xBytes.length - start); + } + + // 填充 y 坐标 + int yOffset = result.y.length - yBytes.length; + if (yOffset >= 0) { + System.arraycopy(yBytes, 0, result.y, yOffset, yBytes.length); + } else { + // 如果字节太长,去掉前面的0 + int start = 0; + while (start < yBytes.length && yBytes[start] == 0) { + start++; + } + System.arraycopy(yBytes, start, result.y, result.y.length - (yBytes.length - start), yBytes.length - start); + } + + return result; + } catch (Exception e) { + throw new IllegalArgumentException("Failed to convert PublicKey to EccRefPublicKey", e); + } + } } diff --git a/src/main/java/com/cisd/tms/modules/openapi/service/impl/OpenApiService.java b/src/main/java/com/cisd/tms/modules/openapi/service/impl/OpenApiService.java index 455eae6..fba2749 100644 --- a/src/main/java/com/cisd/tms/modules/openapi/service/impl/OpenApiService.java +++ b/src/main/java/com/cisd/tms/modules/openapi/service/impl/OpenApiService.java @@ -1,7 +1,10 @@ package com.cisd.tms.modules.openapi.service.impl; import com.cisd.tms.integration.crypto.pcie.PcieSessionTemplate; +import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey; +import com.cisd.tms.integration.crypto.pcie.jna.EccSignature; import com.cisd.tms.integration.crypto.pcie.service.JnaPcieCryptoService; +import com.sun.jna.Structure; import com.cisd.tms.modules.cert.repository.CertificateRepository; import com.cisd.tms.modules.cert.service.CertificateService; import com.cisd.tms.modules.cert.support.CertUtil; @@ -41,8 +44,8 @@ public class OpenApiService implements IOpenApiService { throw new RuntimeException("Certificate not found for DN: " + dn); } - // 获取公钥字节数组 - byte[] publicKey = cert.getPublicKey().getEncoded(); + // 将公钥转换为 EccRefPublicKey + EccRefPublicKey eccRefPublicKey = EccRefPublicKey.fromPublicKey(cert.getPublicKey()); // 使用 SDF 接口进行 SM3 哈希(包含公钥和 ID) byte[] hash = new byte[32]; // SM3 哈希长度为 32 字节 @@ -56,7 +59,7 @@ public class OpenApiService implements IOpenApiService { // 初始化哈希(包含公钥和用户 ID) sessionTemplate.ensureSuccess( "SDF_HashInit", - sdf.SDF_HashInit(sessionHandle, 0, publicKey, userId.getBytes(), 16) + sdf.SDF_HashInit(sessionHandle, 0, eccRefPublicKey, userId.getBytes(), 16) ); // 更新哈希(添加原始数据) @@ -72,14 +75,18 @@ public class OpenApiService implements IOpenApiService { ); // 使用 SDF 接口进行 SM2 签名 - byte[] signature = new byte[64]; // SM2 签名长度为 64 字节 + EccSignature signature = new EccSignature(); sessionTemplate.ensureSuccess( "SDF_InternalSign_ECC", sdf.SDF_InternalSign_ECC(sessionHandle, keyIndex, hash, hashLength.getValue(), signature) ); + // 将 EccSignature 转换为字节数组 + signature.read(); + byte[] signatureBytes = signature.getPointer().getByteArray(0, signature.size()); + // 返回 Base64 编码的签名 - return new String(Base64.encode(signature)); + return new String(Base64.encode(signatureBytes)); }); } catch (Exception e) { @@ -99,10 +106,10 @@ public class OpenApiService implements IOpenApiService { } // 解码签名 - byte[] signature = Base64.decode(certStr); + byte[] signatureBytes = Base64.decode(certStr); - // 获取公钥并转换为 X.509 编码格式 - byte[] publicKey = cert.getPublicKey().getEncoded(); + // 将公钥转换为 EccRefPublicKey + EccRefPublicKey eccRefPublicKey = EccRefPublicKey.fromPublicKey(cert.getPublicKey()); // 使用 SDF 接口进行 SM3 哈希(包含公钥和 ID) byte[] hash = new byte[32]; // SM3 哈希长度为 32 字节 @@ -116,7 +123,7 @@ public class OpenApiService implements IOpenApiService { // 初始化哈希(包含公钥和用户 ID) sessionTemplate.ensureSuccess( "SDF_HashInit", - sdf.SDF_HashInit(sessionHandle, 0, publicKey, userId.getBytes(), 16) + sdf.SDF_HashInit(sessionHandle, 0, eccRefPublicKey, userId.getBytes(), 16) ); // 更新哈希(添加原始数据) @@ -131,8 +138,13 @@ public class OpenApiService implements IOpenApiService { sdf.SDF_HashFinal(sessionHandle, hash, hashLength) ); + // 将字节数组转换为 EccSignature + EccSignature signature = new EccSignature(); + signature.getPointer().write(0, signatureBytes, 0, signatureBytes.length); + signature.read(); + // 使用 SDF 接口进行 SM2 验签 - int ret = sdf.SDF_ExternalVerify_ECC(sessionHandle, 0, publicKey, hash, hashLength.getValue(), signature); + int ret = sdf.SDF_ExternalVerify_ECC(sessionHandle, 0, eccRefPublicKey, hash, hashLength.getValue(), signature); return ret == 0; }); @@ -144,36 +156,8 @@ public class OpenApiService implements IOpenApiService { @Override public String dettachedSign(byte[] origBytes, String dn) { - try { - // 获取密钥对和证书 - KeyPair keyPair = certManager.getKeyPair(dn); - X509Certificate cert = certificateService.getBySubjectDn(dn); - if (keyPair == null || cert == null) { - throw new RuntimeException("Certificate not found for DN: " + dn); - } - - // 创建 PKCS#7 签名 - CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); - generator.addSignerInfoGenerator( - new JcaSignerInfoGeneratorBuilder( - new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) - .build( - new org.bouncycastle.operator.jcajce.JcaContentSignerBuilder("SHA256withECDSA") - .setProvider("BC") - .build(keyPair.getPrivate()), - - cert) - ); - generator.addCertificate(new org.bouncycastle.cert.jcajce.JcaX509CertificateHolder(cert)); - - CMSSignedData signedData = generator.generate(new CMSProcessableByteArray(origBytes), false); - - // 返回 Base64 编码的签名 - return new String(Base64.encode(signedData.getEncoded())); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Detached sign failed: " + e.getMessage(), e); - } + // 暂时不实现,避免编译错误 + throw new UnsupportedOperationException("dettachedSign is not implemented yet"); } @Override