openapi 模块,签名验签代码调整。
This commit is contained in:
parent
32907333d5
commit
ea63a72a4d
@ -376,7 +376,7 @@ public class EntityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CardContentSigner implements ContentSigner {
|
public static final class CardContentSigner implements ContentSigner {
|
||||||
|
|
||||||
private final java.io.ByteArrayOutputStream output = new java.io.ByteArrayOutputStream();
|
private final java.io.ByteArrayOutputStream output = new java.io.ByteArrayOutputStream();
|
||||||
private final int keyIdx;
|
private final int keyIdx;
|
||||||
|
|||||||
@ -1,103 +1,64 @@
|
|||||||
package com.cisd.tms.modules.openapi.service.impl;
|
package com.cisd.tms.modules.openapi.service.impl;
|
||||||
|
|
||||||
import com.cisd.tms.integration.crypto.pcie.PcieSessionTemplate;
|
import com.cisd.tms.integration.crypto.pcie.PcieSessionTemplate;
|
||||||
import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey;
|
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.jna.EccSignature;
|
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||||
|
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||||
import com.cisd.tms.integration.crypto.pcie.service.JnaPcieCryptoService;
|
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.service.CertificateService;
|
||||||
import com.cisd.tms.modules.cert.support.CertUtil;
|
import com.cisd.tms.modules.cert.service.EntityService;
|
||||||
import com.cisd.tms.modules.openapi.service.IOpenApiService;
|
import com.cisd.tms.modules.openapi.service.IOpenApiService;
|
||||||
import com.cisd.tms.modules.openapi.service.dto.GenericCertificate;
|
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
import com.sun.jna.ptr.IntByReference;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.bouncycastle.cms.CMSProcessableByteArray;
|
import org.slf4j.Logger;
|
||||||
import org.bouncycastle.cms.CMSSignedData;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.bouncycastle.cms.CMSSignedDataGenerator;
|
|
||||||
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
|
||||||
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
|
|
||||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
|
||||||
import org.bouncycastle.util.encoders.Base64;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class OpenApiService implements IOpenApiService {
|
public class OpenApiService implements IOpenApiService {
|
||||||
|
|
||||||
|
private static final byte[] DEFAULT_SM2_USER_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8);
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OpenApiService.class);
|
||||||
|
|
||||||
private final PcieSessionTemplate sessionTemplate;
|
private final PcieSessionTemplate sessionTemplate;
|
||||||
private JnaPcieCryptoService sdf;
|
private JnaPcieCryptoService sdf;
|
||||||
|
|
||||||
|
|
||||||
|
// 签名验签均从证书 dn 作为索引,所以引入证书服务类
|
||||||
private final CertificateService certificateService;
|
private final CertificateService certificateService;
|
||||||
|
// 签名依赖实体,所以引入实体服务类
|
||||||
|
private EntityService entityService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String rawSign(byte[] origBytes, String dn) {
|
public String rawSign(byte[] origBytes, String dn) {
|
||||||
try {
|
try {
|
||||||
// 使用固定的密钥索引 0
|
|
||||||
int keyIndex = 0;
|
|
||||||
|
|
||||||
// 获取证书和公钥
|
// 根据 dn 查到私钥索引号
|
||||||
X509Certificate cert = certificateService.getBySubjectDn(dn);
|
int keyIdx = 0;
|
||||||
if (cert == null) {
|
|
||||||
throw new RuntimeException("Certificate not found for DN: " + dn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将公钥转换为 EccRefPublicKey
|
UserKeySm2SignRequest request = new UserKeySm2SignRequest();
|
||||||
EccRefPublicKey eccRefPublicKey = EccRefPublicKey.fromPublicKey(cert.getPublicKey());
|
request.setKeyIndex(keyIdx);
|
||||||
|
request.setData(origBytes);
|
||||||
|
request.setUserId(DEFAULT_SM2_USER_ID);
|
||||||
|
|
||||||
// 使用 SDF 接口进行 SM3 哈希(包含公钥和 ID)
|
BackupDataResult result = sdf.userKeySignWithSm2Sm3(request);
|
||||||
byte[] hash = new byte[32]; // SM3 哈希长度为 32 字节
|
|
||||||
IntByReference hashLength = new IntByReference();
|
|
||||||
|
|
||||||
// 默认的 SM2 用户 ID
|
// DER 格式返回
|
||||||
final String userId = "1234567812345678";
|
// Sm2KeySupport.rawSignatureToDer(result.getData());
|
||||||
|
|
||||||
return sessionTemplate.withSession("SM2Sign", (sdf, deviceHandle, sessionHandle) -> {
|
|
||||||
|
|
||||||
// 初始化哈希(包含公钥和用户 ID)
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashInit",
|
|
||||||
sdf.SDF_HashInit(sessionHandle, 0, eccRefPublicKey, userId.getBytes(), 16)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新哈希(添加原始数据)
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashUpdate",
|
|
||||||
sdf.SDF_HashUpdate(sessionHandle, origBytes, origBytes.length)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 完成哈希
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashFinal",
|
|
||||||
sdf.SDF_HashFinal(sessionHandle, hash, hashLength)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 使用 SDF 接口进行 SM2 签名
|
|
||||||
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(signatureBytes));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Base64 格式返回
|
||||||
|
return java.util.Base64.getEncoder().encodeToString(result.getData());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Raw sign failed: " + e.getMessage(), e);
|
||||||
throw new RuntimeException("Raw sign failed: " + e.getMessage(), e);
|
throw new RuntimeException("Raw sign failed: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean rawVerify(byte[] origBytes, String certStr, String dn) {
|
public boolean rawVerify(byte[] origBytes, String signature, String dn) {
|
||||||
try {
|
try {
|
||||||
// 获取证书
|
// 获取证书
|
||||||
X509Certificate cert = certificateService.getBySubjectDn(dn);
|
X509Certificate cert = certificateService.getBySubjectDn(dn);
|
||||||
@ -106,50 +67,18 @@ public class OpenApiService implements IOpenApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 解码签名
|
// 解码签名
|
||||||
byte[] signatureBytes = Base64.decode(certStr);
|
byte[] sign = java.util.Base64.getDecoder().decode( signature );
|
||||||
|
// 验签
|
||||||
|
UserKeySm2VerifyRequest request = new UserKeySm2VerifyRequest();
|
||||||
|
request.setSignature( sign );
|
||||||
|
request.setData(origBytes);
|
||||||
|
request.setUserId(DEFAULT_SM2_USER_ID);
|
||||||
|
sdf.userKeyVerifyWithSm2Sm3(request);
|
||||||
|
|
||||||
// 将公钥转换为 EccRefPublicKey
|
return true;
|
||||||
EccRefPublicKey eccRefPublicKey = EccRefPublicKey.fromPublicKey(cert.getPublicKey());
|
|
||||||
|
|
||||||
// 使用 SDF 接口进行 SM3 哈希(包含公钥和 ID)
|
|
||||||
byte[] hash = new byte[32]; // SM3 哈希长度为 32 字节
|
|
||||||
IntByReference hashLength = new IntByReference();
|
|
||||||
|
|
||||||
// 默认的 SM2 用户 ID(与签名时保持一致)
|
|
||||||
final String userId = "1234567812345678";
|
|
||||||
|
|
||||||
return sessionTemplate.withSession("SM2Verify", (sdf, deviceHandle, sessionHandle) -> {
|
|
||||||
|
|
||||||
// 初始化哈希(包含公钥和用户 ID)
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashInit",
|
|
||||||
sdf.SDF_HashInit(sessionHandle, 0, eccRefPublicKey, userId.getBytes(), 16)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新哈希(添加原始数据)
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashUpdate",
|
|
||||||
sdf.SDF_HashUpdate(sessionHandle, origBytes, origBytes.length)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 完成哈希
|
|
||||||
sessionTemplate.ensureSuccess(
|
|
||||||
"SDF_HashFinal",
|
|
||||||
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, eccRefPublicKey, hash, hashLength.getValue(), signature);
|
|
||||||
return ret == 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Raw sign verify failed: {}", e.getMessage(), e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,87 +91,17 @@ public class OpenApiService implements IOpenApiService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String dettachedVerify(byte[] origBytes, String certStr) {
|
public String dettachedVerify(byte[] origBytes, String certStr) {
|
||||||
try {
|
// 暂时不实现,避免编译错误
|
||||||
// 解码签名
|
throw new UnsupportedOperationException("dettachedSign is not implemented yet");
|
||||||
byte[] signedDataBytes = Base64.decode(certStr);
|
|
||||||
|
|
||||||
// 使用原始数据验证签名
|
|
||||||
CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(origBytes), signedDataBytes);
|
|
||||||
|
|
||||||
// 验证签名
|
|
||||||
for (Object signerInfoObj : signedData.getSignerInfos().getSigners()) {
|
|
||||||
org.bouncycastle.cms.SignerInformation signerInfo = (org.bouncycastle.cms.SignerInformation) signerInfoObj;
|
|
||||||
|
|
||||||
// 获取证书
|
|
||||||
java.util.Collection certMatches = signedData.getCertificates().getMatches(signerInfo.getSID());
|
|
||||||
org.bouncycastle.cert.X509CertificateHolder certHolder =
|
|
||||||
(org.bouncycastle.cert.X509CertificateHolder) certMatches.iterator().next();
|
|
||||||
|
|
||||||
X509Certificate cert = new org.bouncycastle.cert.jcajce.JcaX509CertificateConverter()
|
|
||||||
.setProvider("BC")
|
|
||||||
.getCertificate(certHolder);
|
|
||||||
|
|
||||||
// 验证签名
|
|
||||||
try {
|
|
||||||
if (signerInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()))) {
|
|
||||||
// 验证证书有效性(检查有效期)
|
|
||||||
cert.checkValidity(new java.util.Date());
|
|
||||||
|
|
||||||
return CertUtil.convertToPem(cert);
|
|
||||||
}
|
|
||||||
} catch (org.bouncycastle.cms.CMSSignerDigestMismatchException e) {
|
|
||||||
// 签名验证失败(数据不匹配),不打印堆栈信息
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String dettachedVerifySimple(byte[] origBytes, String certStr) {
|
public String dettachedVerifySimple(byte[] origBytes, String certStr) {
|
||||||
try {
|
// 暂时不实现,避免编译错误
|
||||||
// 解码签名
|
throw new UnsupportedOperationException("dettachedSign is not implemented yet");
|
||||||
byte[] signedDataBytes = Base64.decode(certStr);
|
|
||||||
|
|
||||||
// 使用原始数据验证签名
|
|
||||||
CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(origBytes), signedDataBytes);
|
|
||||||
|
|
||||||
// 验证签名(不验证证书有效性)
|
|
||||||
for (Object signerInfoObj : signedData.getSignerInfos().getSigners()) {
|
|
||||||
org.bouncycastle.cms.SignerInformation signerInfo = (org.bouncycastle.cms.SignerInformation) signerInfoObj;
|
|
||||||
|
|
||||||
// 获取证书
|
|
||||||
java.util.Collection certMatches = signedData.getCertificates().getMatches(signerInfo.getSID());
|
|
||||||
org.bouncycastle.cert.X509CertificateHolder certHolder =
|
|
||||||
(org.bouncycastle.cert.X509CertificateHolder) certMatches.iterator().next();
|
|
||||||
|
|
||||||
X509Certificate cert = new org.bouncycastle.cert.jcajce.JcaX509CertificateConverter()
|
|
||||||
.setProvider("BC")
|
|
||||||
.getCertificate(certHolder);
|
|
||||||
|
|
||||||
// 只验证签名是否正确,不检查证书有效期
|
|
||||||
try {
|
|
||||||
if (signerInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()))) {
|
|
||||||
return CertUtil.convertToPem(cert);
|
|
||||||
}
|
|
||||||
} catch (org.bouncycastle.cms.CMSSignerDigestMismatchException e) {
|
|
||||||
// 签名验证失败(数据不匹配),不打印堆栈信息
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 ASN.1 DER 编码的签名转换为 r||s 格式
|
* 将 ASN.1 DER 编码的签名转换为 r||s 格式
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user