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 int keyIdx;
|
||||
|
||||
@ -1,103 +1,64 @@
|
||||
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.model.BackupDataResult;
|
||||
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.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;
|
||||
import com.cisd.tms.modules.cert.service.EntityService;
|
||||
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 org.bouncycastle.cms.CMSProcessableByteArray;
|
||||
import org.bouncycastle.cms.CMSSignedData;
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
|
||||
@RequiredArgsConstructor
|
||||
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 JnaPcieCryptoService sdf;
|
||||
|
||||
|
||||
// 签名验签均从证书 dn 作为索引,所以引入证书服务类
|
||||
private final CertificateService certificateService;
|
||||
// 签名依赖实体,所以引入实体服务类
|
||||
private EntityService entityService;
|
||||
|
||||
@Override
|
||||
public String rawSign(byte[] origBytes, String dn) {
|
||||
try {
|
||||
// 使用固定的密钥索引 0
|
||||
int keyIndex = 0;
|
||||
|
||||
// 获取证书和公钥
|
||||
X509Certificate cert = certificateService.getBySubjectDn(dn);
|
||||
if (cert == null) {
|
||||
throw new RuntimeException("Certificate not found for DN: " + dn);
|
||||
}
|
||||
// 根据 dn 查到私钥索引号
|
||||
int keyIdx = 0;
|
||||
|
||||
// 将公钥转换为 EccRefPublicKey
|
||||
EccRefPublicKey eccRefPublicKey = EccRefPublicKey.fromPublicKey(cert.getPublicKey());
|
||||
UserKeySm2SignRequest request = new UserKeySm2SignRequest();
|
||||
request.setKeyIndex(keyIdx);
|
||||
request.setData(origBytes);
|
||||
request.setUserId(DEFAULT_SM2_USER_ID);
|
||||
|
||||
// 使用 SDF 接口进行 SM3 哈希(包含公钥和 ID)
|
||||
byte[] hash = new byte[32]; // SM3 哈希长度为 32 字节
|
||||
IntByReference hashLength = new IntByReference();
|
||||
BackupDataResult result = sdf.userKeySignWithSm2Sm3(request);
|
||||
|
||||
// 默认的 SM2 用户 ID
|
||||
final String userId = "1234567812345678";
|
||||
|
||||
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));
|
||||
});
|
||||
// DER 格式返回
|
||||
// Sm2KeySupport.rawSignatureToDer(result.getData());
|
||||
|
||||
// Base64 格式返回
|
||||
return java.util.Base64.getEncoder().encodeToString(result.getData());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Raw sign failed: " + e.getMessage(), e);
|
||||
throw new RuntimeException("Raw sign failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean rawVerify(byte[] origBytes, String certStr, String dn) {
|
||||
public boolean rawVerify(byte[] origBytes, String signature, String dn) {
|
||||
try {
|
||||
// 获取证书
|
||||
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
|
||||
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;
|
||||
});
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("Raw sign verify failed: {}", e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -162,87 +91,17 @@ public class OpenApiService implements IOpenApiService {
|
||||
|
||||
@Override
|
||||
public String dettachedVerify(byte[] origBytes, String certStr) {
|
||||
try {
|
||||
// 解码签名
|
||||
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;
|
||||
}
|
||||
// 暂时不实现,避免编译错误
|
||||
throw new UnsupportedOperationException("dettachedSign is not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dettachedVerifySimple(byte[] origBytes, String certStr) {
|
||||
try {
|
||||
// 解码签名
|
||||
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;
|
||||
}
|
||||
// 暂时不实现,避免编译错误
|
||||
throw new UnsupportedOperationException("dettachedSign is not implemented yet");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将 ASN.1 DER 编码的签名转换为 r||s 格式
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user