This commit is contained in:
cheney
2026-05-21 15:56:35 +08:00
commit 970c631e52
21 changed files with 2054 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
/target/classes/com/sunyard/cisd/device/tool/CMSSignatureUtil.class
/target/classes/com/sunyard/cisd/device/tool/CMSUtil.class
/target/classes/com/sunyard/cisd/device/tool/DeviceFingerprint.class
/target/classes/com/sunyard/cisd/device/tool/DeviceFingerprintService.class
/target/classes/com/sunyard/cisd/device/tool/Main.class
/target/classes/com/sunyard/cisd/device/tool/SdfDeviceInfo.class
/target/classes/com/sunyard/cisd/device/tool/SdfNativeLibrary.class
/target/classes/com/sunyard/cisd/device/tool/SM2SignedEnvelopeUtil$DecryptedResult.class
/target/classes/com/sunyard/cisd/device/tool/SM2SignedEnvelopeUtil$SM2KeyPair.class
/target/classes/com/sunyard/cisd/device/tool/SM2SignedEnvelopeUtil.class
/target/classes/com/sunyard/cisd/device/tool/SM2Util.class
/target/classes/com/sunyard/cisd/device/tool/SM3Util.class
/target/classes/CFCA_TEST_CS_SM2_CA.cer
/target/classes/fingerprint_sm2_private_key.pem
/target/classes/fingerprint_sm2_public_key.pem
/target/classes/mac_sm2_private_key.pem
/target/classes/mac_sm2_public_key.pem
/target/maven-archiver/pom.properties
/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
/target/test-classes/com/sunyard/cisd/CMSSignatureTest.class
/target/test-classes/com/sunyard/cisd/SM2UtilTest.class
/target/sectool-1.0.3.jar
/target/sectool-1.0.3-jar-with-dependencies.jar
+1
View File
@@ -0,0 +1 @@
MIIHQgYJKoZIhvcNAQcEoIIHMzCCBy8CAQExgegwgeUCAQAwVzBDMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxITAfBgNVBAMMGFNIRUNBIFNNMiBJZGVudGl0eSBDQSBHMQIQcY3xZSj2byIgOfQlOP4wODALBgkqgRzPVQGCLQMEejB4AiBn3HNwe+kHu6UWog0utsfHl1bBw5ocnpvBoDvAQf9onwIgcMUv9zI9qf34CgGAxjGBzFBlgMBh1w8h9uKrBCsLSnAEIAnK73EioT8N+W2DncQwR1pcKR3M3wLCCFVxDIy2QhzHBBBsEH3yAdMXbnke0TtaMcJhMQwwCgYIKoEcz1UBgxEwggFLBgkqhkiG9w0BBwEwCgYIKoEcz1UBaAGAggEwg8qCAFghGkdJGOWi6nhkT971c22k4ggdhXWyx3CqRkUSE5oTU2E1Z9+CxW7mg1Z5GV1SCUvYH1olZ1VXZfXQNw15rSlfdakeEKydr9hnGCNgqWAx9uWF0NN5+XZIknqu8oXPJXl2PyY/sMhglEIaPVUfEG69TfYf7T+dr2m0Tq2stcJsJYCwa0i7LMqx0HnF72cWOnqufe1klIaFTwvkM4wdYjtShikebC+q3ZZ0uPtAha5WxcYKrmGF5vOzNlDR9YmcebZKaAZOixS7wdA0fd8X+XeUUC525BddcOXJEjMwE4dMTl0PiCWtmQu0OCXM0k/qgFKvSfi/01bu5mhFOmQ5wsSGFJQXfG9MogPJG22Y2h4mThNXrfR617d6+Y6H2QFOOyo+tig2lPFDAlhbfKCCA68wggOrMIIDUaADAgECAhAzrxJMiUqoQRIbFwyZQvcbMAoGCCqBHM9VAYN1MEMxCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEhMB8GA1UEAwwYU0hFQ0EgU00yIElkZW50aXR5IENBIEcxMB4XDTI2MDQyMjA5MDUxNVoXDTI3MDQyMjE1NTk1OVowgb4xCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAnkuIrmtbfluIIxEjAQBgNVBAcMCeS4iua1t+W4gjE8MDoGA1UECgwz5Lit5Zu95Yac5Lia6ZO26KGM6IKh5Lu95pyJ6ZmQ5YWs5Y+45LiK5rW35biC5YiG6KGMMUkwRwYDVQQDDEDvvIjmtYvor5Ux77yJ5Lit5Zu95Yac5Lia6ZO26KGM6IKh5Lu95pyJ6ZmQ5YWs5Y+45LiK5rW35biC5YiG6KGMMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEAxHGtKigioOKSW38ag3C5pnzQZzL2b6qFU5a6I3V1/w08jI9JOryztM6PrmBaQfTOCVShNFEznnbVl3sE2Ow36OCAakwggGlMB8GA1UdIwQYMBaAFGh8L5suaKLfzhERVBGmtg5s7iUgMB0GA1UdDgQWBBRejj4IJGM/m6gwyOl0ZX4+paB8VDAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMEYGA1UdIAQ/MD0wOwYJKoEchu86AQMBMC4wLAYIKwYBBQUHAgEWIGh0dHBzOi8vd3d3LnNoZWNhLmNvbS9yZXBvc2l0b3J5MAkGA1UdEwQCMAAwWAYDVR0fBFEwTzBNoEugSYZHaHR0cDovL2xkYXAyLnNoZWNhLmNvbS81NzA0NGFkNC85ZTk5LzE3NjMvMDgzMTRiODEvOWNlYTc4NGIxNzczZDBmOS5jcmwwgYYGCCsGAQUFBwEBBHoweDA4BggrBgEFBQcwAYYsaHR0cDovL29jc3AzLnNoZWNhLmNvbS9vY3NwL3NoZWNhL3NoZWNhLm9jc3AwPAYIKwYBBQUHMAKGMGh0dHA6Ly9jZXJ0cy5nbG9iYWwuc2hlY2EuY29tL3NoZWNhc20yaWRjYWcxLmNlcjAKBggqgRzPVQGDdQNIADBFAiB92EaDudEpOvFnQynw+2QT7DKIXOIwuJ+vcmtUQ2xM5QIhAMML15p65/z812BTu27mhtgQypIDnnwS82SAvyWLsWDeMYIBLTCCASkCAQEwVzBDMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxITAfBgNVBAMMGFNIRUNBIFNNMiBJZGVudGl0eSBDQSBHMQIQM68STIlKqEESGxcMmUL3GzAKBggqgRzPVQGDEaBqMBkGCSqGSIb3DQEJAzEMBgoqgRzPVQYBBAIBMBwGCSqGSIb3DQEJBTEPFw0yNjA1MTIwOTEwMDFaMC8GCSqGSIb3DQEJBDEiBCAwWUT2JBmVnGwTk+UVlXkgP8KmdPnZkGMtOyHg2wJtsjALBgkqgRzPVQGCLQEERjBEAiBM4MOj5QNqVzOz1GPQdqt+0cpQXxRak6S1IboEe7hLwQIgR5aUyfFtnKutpbXxoetC5Y0PUKooVp0FrgWzgT2/8vc=
+1
View File
@@ -0,0 +1 @@
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
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sunyard.cisd</groupId>
<artifactId>sectool</artifactId>
<version>1.0.3</version>
<name>sectool</name>
<description>设备指纹信息获取工具</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<distributionManagement>
<snapshotRepository>
<id>nexus-own</id>
<name>repo-snapshot</name>
<url>${SnapshotRepository}</url>
</snapshotRepository>
<repository>
<id>nexus-own</id>
<name>repo-release</name>
<url>${ReleaseRepository}</url>
</repository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.42</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.sunyard.cisd.device.tool.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.sunyard.cisd.device.tool.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,130 @@
package com.sunyard.cisd.device.tool;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Collection;
public class CMSSignatureUtil {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static boolean verifyCMSSignature(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return verifyCMSSignature(cmsData);
}
public static boolean verifyCMSSignature(byte[] cmsData) throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
Store certStore = cmsSignedData.getCertificates();
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
Collection certCollection = certStore.getMatches(signer.getSID());
if (certCollection.isEmpty()) {
throw new CMSException("未找到签名证书");
}
X509CertificateHolder certHolder = (X509CertificateHolder) certCollection.iterator().next();
X509Certificate cert = convertCertificate(certHolder);
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
return true;
}
} catch (Exception e) {
System.err.println("签名验证失败: " + e.getMessage());
}
}
return false;
}
public static boolean verifyCMSSignatureWithCertificate(String base64CmsData, X509Certificate publicCert) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return verifyCMSSignatureWithCertificate(cmsData, publicCert);
}
public static boolean verifyCMSSignatureWithCertificate(byte[] cmsData, X509Certificate publicCert) throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(publicCert))) {
return true;
}
} catch (Exception e) {
System.err.println("使用指定证书验证失败: " + e.getMessage());
}
}
return false;
}
public static byte[] extractContent(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return extractContent(cmsData);
}
public static byte[] extractContent(byte[] cmsData) throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return (byte[]) cmsSignedData.getSignedContent().getContent();
}
public static X509Certificate loadCertificateFromBytes(byte[] certBytes) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certBytes));
}
public static X509Certificate loadCertificateFromBase64(String base64Cert) throws Exception {
byte[] certBytes = Base64.getDecoder().decode(base64Cert);
return loadCertificateFromBytes(certBytes);
}
private static X509Certificate convertCertificate(X509CertificateHolder certHolder) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certHolder.getEncoded()));
}
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("用法: java CMSSignatureUtil <base64_cms_data> [base64_certificate]");
return;
}
try {
String cmsData = args[0];
if (args.length >= 2) {
String certBase64 = args[1];
X509Certificate cert = loadCertificateFromBase64(certBase64);
boolean result = verifyCMSSignatureWithCertificate(cmsData, cert);
System.out.println("使用指定证书验签结果: " + result);
} else {
boolean result = verifyCMSSignature(cmsData);
System.out.println("使用CMS内置证书验签结果: " + result);
}
byte[] content = extractContent(cmsData);
System.out.println("提取的内容长度: " + content.length + " bytes");
} catch (Exception e) {
System.err.println("验签失败: " + e.getMessage());
e.printStackTrace();
}
}
}
@@ -0,0 +1,162 @@
package com.sunyard.cisd.device.tool;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Collection;
public class CMSUtil {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static String detectCMSType(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return detectCMSType(cmsData);
}
public static String detectCMSType(byte[] cmsData) throws Exception {
try (ASN1InputStream asn1InputStream = new ASN1InputStream(cmsData)) {
ContentInfo contentInfo = ContentInfo.getInstance(asn1InputStream.readObject());
String typeOid = contentInfo.getContentType().getId();
if (typeOid.equals(CMSObjectIdentifiers.signedData.getId())) {
return "SignedData";
} else if (typeOid.equals(CMSObjectIdentifiers.envelopedData.getId())) {
return "EnvelopedData";
} else if (typeOid.equals(CMSObjectIdentifiers.signedAndEnvelopedData.getId())) {
return "SignedAndEnvelopedData";
} else if (typeOid.equals(CMSObjectIdentifiers.digestedData.getId())) {
return "DigestedData";
} else if (typeOid.equals(CMSObjectIdentifiers.encryptedData.getId())) {
return "EncryptedData";
} else {
return "Unknown: " + typeOid;
}
}
}
public static boolean verifySignedData(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
return verifySignedData(cmsData);
}
public static boolean verifySignedData(byte[] cmsData) throws Exception {
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return verifySignedData(cmsSignedData);
}
public static boolean verifySignedData(CMSSignedData cmsSignedData) throws Exception {
Store certStore = cmsSignedData.getCertificates();
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
Collection certCollection = certStore.getMatches(signer.getSID());
if (certCollection.isEmpty()) {
System.err.println("未找到签名证书");
continue;
}
X509CertificateHolder certHolder = (X509CertificateHolder) certCollection.iterator().next();
X509Certificate cert = convertCertificate(certHolder);
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
return true;
}
} catch (Exception e) {
System.err.println("签名验证失败: " + e.getMessage());
}
}
return false;
}
public static boolean verifySignedDataWithCertificate(String base64CmsData, X509Certificate publicCert) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return verifySignedDataWithCertificate(cmsSignedData, publicCert);
}
public static boolean verifySignedDataWithCertificate(CMSSignedData cmsSignedData, X509Certificate publicCert) throws Exception {
SignerInformationStore signerStore = cmsSignedData.getSignerInfos();
for (Object signerObj : signerStore.getSigners()) {
SignerInformation signer = (SignerInformation) signerObj;
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(publicCert))) {
return true;
}
} catch (Exception e) {
System.err.println("使用指定证书验证失败: " + e.getMessage());
}
}
return false;
}
public static byte[] extractSignedContent(String base64CmsData) throws Exception {
byte[] cmsData = Base64.getDecoder().decode(base64CmsData);
CMSSignedData cmsSignedData = new CMSSignedData(cmsData);
return (byte[]) cmsSignedData.getSignedContent().getContent();
}
public static X509Certificate loadCertificateFromBytes(byte[] certBytes) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certBytes));
}
public static X509Certificate loadCertificateFromBase64(String base64Cert) throws Exception {
byte[] certBytes = Base64.getDecoder().decode(base64Cert);
return loadCertificateFromBytes(certBytes);
}
private static X509Certificate convertCertificate(X509CertificateHolder certHolder) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
return (X509Certificate) cf.generateCertificate(new java.io.ByteArrayInputStream(certHolder.getEncoded()));
}
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("用法: java CMSUtil <base64_cms_data>");
return;
}
try {
String cmsData = args[0];
String type = detectCMSType(cmsData);
System.out.println("CMS类型: " + type);
System.out.println();
boolean verified = false;
if (type.equals("SignedData")) {
verified = verifySignedData(cmsData);
System.out.println("SignedData验签结果: " + verified);
} else if (type.equals("EnvelopedData")) {
System.out.println("这是一个数字信封(EnvelopedData),需要私钥解密后才能验证签名");
} else if (type.equals("SignedAndEnvelopedData")) {
System.out.println("这是一个SignedAndEnvelopedData(同时签名和加密)");
System.out.println("需要使用对应的私钥解密后才能验证签名");
}
} catch (Exception e) {
System.err.println("处理失败: " + e.getMessage());
e.printStackTrace();
}
}
}
@@ -0,0 +1,83 @@
package com.sunyard.cisd.device.tool;
public class DeviceFingerprint {
private String motherboardSerialNumber;
private String deviceSerialNumber;
private String cpuModel;
private String cpuSerialNumber;
private String memorySize;
private String firstNetworkMacAddress;
private String hardDiskSerialNumber;
public DeviceFingerprint() {
}
public String getMotherboardSerialNumber() {
return motherboardSerialNumber;
}
public void setMotherboardSerialNumber(String motherboardSerialNumber) {
this.motherboardSerialNumber = motherboardSerialNumber;
}
public String getDeviceSerialNumber() {
return deviceSerialNumber;
}
public void setDeviceSerialNumber(String deviceSerialNumber) {
this.deviceSerialNumber = deviceSerialNumber;
}
public String getCpuModel() {
return cpuModel;
}
public void setCpuModel(String cpuModel) {
this.cpuModel = cpuModel;
}
public String getCpuSerialNumber() {
return cpuSerialNumber;
}
public void setCpuSerialNumber(String cpuSerialNumber) {
this.cpuSerialNumber = cpuSerialNumber;
}
public String getMemorySize() {
return memorySize;
}
public void setMemorySize(String memorySize) {
this.memorySize = memorySize;
}
public String getFirstNetworkMacAddress() {
return firstNetworkMacAddress;
}
public void setFirstNetworkMacAddress(String firstNetworkMacAddress) {
this.firstNetworkMacAddress = firstNetworkMacAddress;
}
public String getHardDiskSerialNumber() {
return hardDiskSerialNumber;
}
public void setHardDiskSerialNumber(String hardDiskSerialNumber) {
this.hardDiskSerialNumber = hardDiskSerialNumber;
}
@Override
public String toString() {
return "DeviceFingerprint{" +
"motherboardSerialNumber='" + motherboardSerialNumber + '\'' +
", deviceSerialNumber='" + deviceSerialNumber + '\'' +
", cpuModel='" + cpuModel + '\'' +
", cpuSerialNumber='" + cpuSerialNumber + '\'' +
", memorySize='" + memorySize + '\'' +
", firstNetworkMacAddress='" + firstNetworkMacAddress + '\'' +
", hardDiskSerialNumber='" + hardDiskSerialNumber + '\'' +
'}';
}
}
@@ -0,0 +1,254 @@
package com.sunyard.cisd.device.tool;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class DeviceFingerprintService {
private static final String SDF_LIBRARY_PATH = "/home/tms/libs/libsdf_syd1408-x64.so.1.0.0";
private static SdfNativeLibrary sdfLibrary = null;
private static boolean libraryLoaded = false;
private static String loadError = null;
static {
System.out.println("[DEBUG] Attempting to load SDF library from: " + SDF_LIBRARY_PATH);
File libFile = new File(SDF_LIBRARY_PATH);
if (libFile.exists()) {
System.out.println("[DEBUG] Library file exists: " + SDF_LIBRARY_PATH);
System.out.println("[DEBUG] File size: " + libFile.length() + " bytes");
} else {
System.out.println("[ERROR] Library file not found: " + SDF_LIBRARY_PATH);
loadError = "Library file not found";
}
try {
sdfLibrary = Native.load(SDF_LIBRARY_PATH, SdfNativeLibrary.class);
libraryLoaded = true;
System.out.println("[DEBUG] SDF library loaded successfully");
} catch (UnsatisfiedLinkError e) {
loadError = "UnsatisfiedLinkError: " + e.getMessage();
System.err.println("[ERROR] Failed to load SDF library (UnsatisfiedLinkError): " + e.getMessage());
System.err.println("[ERROR] Cause: " + (e.getCause() != null ? e.getCause().getMessage() : "null"));
} catch (Exception e) {
loadError = "Exception: " + e.getMessage();
System.err.println("[ERROR] Failed to load SDF library (Exception): " + e.getClass().getName() + " - " + e.getMessage());
e.printStackTrace();
}
}
public DeviceFingerprint getDeviceFingerprint() {
DeviceFingerprint fingerprint = new DeviceFingerprint();
String cpuSerialNumber = getCpuSerialNumber();
fingerprint.setCpuSerialNumber(cpuSerialNumber);
fingerprint.setMotherboardSerialNumber(cpuSerialNumber);
fingerprint.setCpuModel(getCpuModel());
fingerprint.setMemorySize(getMemorySize());
fingerprint.setFirstNetworkMacAddress(getFirstNetworkMacAddress());
fingerprint.setHardDiskSerialNumber(getHardDiskSerialNumber());
fingerprint.setDeviceSerialNumber(getDeviceSerialNumber());
return fingerprint;
}
private String getCpuModel() {
return executeCommand("sudo dmidecode -t processor | grep \"Version\" | awk -F\\ '{print $2$3$4}'");
}
private String getCpuSerialNumber() {
return executeCommand("sudo dmidecode -t processor | grep \"Serial Number\" | awk -F\\ '{print $3}'");
}
private String getHardDiskSerialNumber() {
return executeCommand("lsblk -o SERIAL /dev/sda | awk 'NR==2{print $1}'");
}
private String getMemorySize() {
String result = executeCommand("free -h | grep Mem | awk '{print $2}'");
return result != null && !result.isEmpty() ? result : "Unknown";
}
private String getFirstNetworkMacAddress() {
String result = executeCommand("ip link show | awk '/ether/ {print $2; exit}'");
return result != null && !result.isEmpty() ? result : "Unknown";
}
private static String zeroTerminatedString(byte[] value) {
int len = 0;
while (len < value.length && value[len] != 0) {
len++;
}
return new String(value, 0, len, StandardCharsets.UTF_8).trim();
}
private String getDeviceSerialNumber() {
System.out.println("[DEBUG] getDeviceSerialNumber() called");
System.out.println("[DEBUG] Library loaded: " + libraryLoaded + ", sdfLibrary: " + (sdfLibrary != null ? "not null" : "null"));
if (!libraryLoaded || sdfLibrary == null) {
System.err.println("[ERROR] SDF library not loaded. Cannot get device serial number.");
System.err.println("[ERROR] Load error: " + loadError);
return "Unknown";
}
Pointer deviceHandle = null;
Pointer sessionHandle = null;
try {
System.out.println("[DEBUG] Calling SDF_OpenDevice...");
PointerByReference phDeviceHandle = new PointerByReference();
int ret = sdfLibrary.SDF_OpenDevice(phDeviceHandle);
System.out.println("[DEBUG] SDF_OpenDevice returned: " + ret);
if (ret != 0) {
System.err.println("[ERROR] SDF_OpenDevice failed with error code: " + ret);
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
return "Unknown";
}
deviceHandle = phDeviceHandle.getValue();
System.out.println("[DEBUG] Device handle obtained: " + deviceHandle);
System.out.println("[DEBUG] Calling SDF_OpenSession...");
PointerByReference phSessionHandle = new PointerByReference();
ret = sdfLibrary.SDF_OpenSession(deviceHandle, phSessionHandle);
System.out.println("[DEBUG] SDF_OpenSession returned: " + ret);
if (ret != 0) {
System.err.println("[ERROR] SDF_OpenSession failed with error code: " + ret);
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
return "Unknown";
}
sessionHandle = phSessionHandle.getValue();
System.out.println("[DEBUG] Session handle obtained: " + sessionHandle);
System.out.println("[DEBUG] Calling SDF_GetDeviceInfo...");
SdfDeviceInfo info = new SdfDeviceInfo();
ret = sdfLibrary.SDF_GetDeviceInfo(sessionHandle, info);
System.out.println("[DEBUG] SDF_GetDeviceInfo returned: " + ret);
if (ret != 0) {
System.err.println("[ERROR] SDF_GetDeviceInfo failed with error code: " + ret);
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
return "Unknown";
}
String issuerName = zeroTerminatedString(info.getIssuerName());
String deviceName = zeroTerminatedString(info.getDeviceName());
String deviceSerial = zeroTerminatedString(info.getDeviceSerial());
System.out.println("[DEBUG] Device info retrieved:");
System.out.println("[DEBUG] IssuerName: '" + issuerName + "'");
System.out.println("[DEBUG] DeviceName: '" + deviceName + "'");
System.out.println("[DEBUG] DeviceSerial: '" + deviceSerial + "'");
if (deviceSerial == null || deviceSerial.isEmpty()) {
System.err.println("[WARNING] Device serial number is empty");
return "Unknown";
}
return deviceSerial;
} catch (UnsatisfiedLinkError e) {
System.err.println("[ERROR] UnsatisfiedLinkError when calling SDF API: " + e.getMessage());
e.printStackTrace();
return "Unknown";
} catch (Exception e) {
System.err.println("[ERROR] Exception when calling SDF API: " + e.getClass().getName() + " - " + e.getMessage());
e.printStackTrace();
return "Unknown";
} finally {
if (sessionHandle != null) {
try {
System.out.println("[DEBUG] Closing session handle: " + sessionHandle);
sdfLibrary.SDF_CloseSession(sessionHandle);
} catch (Exception e) {
System.err.println("[ERROR] Error closing session: " + e.getMessage());
}
}
if (deviceHandle != null) {
try {
System.out.println("[DEBUG] Closing device handle: " + deviceHandle);
sdfLibrary.SDF_CloseDevice(deviceHandle);
} catch (Exception e) {
System.err.println("[ERROR] Error closing device: " + e.getMessage());
}
}
}
}
private String getErrorMessage(int errorCode) {
switch (errorCode) {
case 0:
return "Success";
case -1:
return "General error";
case -2:
return "Invalid parameter";
case -3:
return "Memory allocation failed";
case -4:
return "Device not found";
case -5:
return "Device not opened";
case -6:
return "Session not opened";
case -7:
return "Operation not supported";
case -8:
return "Key not found";
case -9:
return "Key access denied";
case -10:
return "Invalid key";
case -11:
return "Invalid signature";
case -12:
return "Invalid certificate";
case -13:
return "Buffer too small";
case -14:
return "Timeout";
case -15:
return "Hardware error";
default:
return "Unknown error code: " + errorCode;
}
}
private String executeCommand(String command) {
try {
Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
StringBuilder output = new StringBuilder();
while ((line = reader.readLine()) != null) {
output.append(line);
}
String errorOutput = "";
while ((line = errorReader.readLine()) != null) {
errorOutput += line;
}
int exitCode = process.waitFor();
if (exitCode == 0) {
String result = output.toString().trim();
return result.isEmpty() ? "Unknown" : result;
} else {
System.err.println("[ERROR] Command '" + command + "' failed with exit code " + exitCode + ": " + errorOutput);
return "Unknown";
}
} catch (Exception e) {
System.err.println("[ERROR] Error executing command '" + command + "': " + e.getMessage());
return "Unknown";
}
}
}
@@ -0,0 +1,504 @@
package com.sunyard.cisd.device.tool;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Map;
public class Main {
private static final String DEVICE_DIR = "/home/tms/device";
public static final String SIGN_FILE = DEVICE_DIR + "/dev.sign";
private static final String SIGN_SM3_FILE = DEVICE_DIR + "/dev.sign.sm3";
private static final String PUBLIC_KEY_FILE = DEVICE_DIR + "/dev.fingerprint.pub";
private static final String PUBLIC_KEY_SM3_FILE = DEVICE_DIR + "/dev.fingerprint.pub.sm3";
public static final String FINGERPRINT_DATA_FILE = DEVICE_DIR + "/dev.fingerprint.data";
private static final String FINGERPRINT_PRIVATE_KEY_PATH = "/fingerprint_sm2_private_key.pem";
public static final String FINGERPRINT_PUBLIC_KEY_PATH = "/fingerprint_sm2_public_key.pem";
private static final String MAC_PRIVATE_KEY_PATH = "/mac_sm2_private_key.pem";
public static final String MAC_PUBLIC_KEY_PATH = "/mac_sm2_public_key.pem";
private static final String ROOT_CERT_FILE = "/CFCA_TEST_CS_SM2_CA.cer";
private static final String ROOT_CERT_OUTPUT_FILE = DEVICE_DIR + "/CFCA_TEST_CS_SM2_CA.cer";
private static final String ROOT_CERT_SIGN_FILE = DEVICE_DIR + "/rootcert.sign";
private static final String MAC_PUBLIC_KEY_OUTPUT_FILE = DEVICE_DIR + "/dev.mac.pub";
private static final String MAC_PUBLIC_KEY_SM3_FILE = DEVICE_DIR + "/dev.mac.pub.sm3";
public static final String MAC_LIST_FILE = "/home/tms/mac.list";
public static final String MAC_SIGN_FILE = DEVICE_DIR + "/dev.mac.sign";
public static final String CMEP_MAC_LIST_FILE = "/home/cmep4i/cmep.mac.list";
public static final String CMEP_MAC_SIGN_FILE = "/home/cmep4i/cmep.mac.sign";
public static final String[] MAC_TARGETS = {
"/home/tms/tms-framework.jar",
"/home/tms/config",
"/home/tms/libs",
"/home/tms/web",
"/home/tms/bin",
"/home/tms/scripts/tms.sh"
};
public static final String[] CMEP_TARGETS = {
"/home/cmep4i/cmsp/CMEP-CMSP.jar",
"/home/cmep4i/cmtp/CMEP-CMTP.jar"
};
public static void main(String[] args) {
if (args.length == 0) {
printHelp();
return;
}
String command = args[0];
try {
switch (command) {
case "help":
printHelp();
break;
case "info":
showDeviceInfo();
break;
case "fingerprint-gen":
generateFingerprint();
break;
case "fingerprint-vertify":
verifyFingerprint();
break;
case "tms-mac-gen":
generateMAC();
break;
case "tms-mac-vertify":
verifyMAC();
break;
case "cmep-mac-gen":
generateCMEPMAC();
break;
case "cmep-mac-vertify":
verifyCMEPMAC();
break;
case "rootcert-mac-gen":
generateRootCertMAC();
break;
case "rootcert-mac-vertify":
verifyRootCertMAC();
break;
default:
System.err.println("未知命令: " + command);
printHelp();
break;
}
} catch (Exception e) {
System.err.println("处理过程中发生错误: " + e.getMessage());
e.printStackTrace();
}
}
private static void printHelp() {
System.out.println("设备指纹工具 - 使用说明");
System.out.println();
System.out.println("可用命令:");
System.out.println(" help - 显示帮助信息");
System.out.println(" info - 获取并显示设备信息");
System.out.println(" fingerprint-gen - 获取设备信息并生成设备指纹输出到文件");
System.out.println(" fingerprint-vertify - 获取设备信息并验证设备指纹");
System.out.println(" tms-mac-gen - 生成TMS系统文件MAC校验值并签名");
System.out.println(" tms-mac-vertify - 验证TMS系统文件MAC校验值");
System.out.println(" cmep-mac-gen - 生成CMEP文件MAC校验值并签名");
System.out.println(" cmep-mac-vertify - 验证CMEP文件MAC校验值");
System.out.println(" rootcert-mac-gen - 生成根证书MAC签名");
System.out.println(" rootcert-mac-vertify - 验证根证书MAC签名");
System.out.println();
}
private static void showDeviceInfo() throws Exception {
DeviceFingerprintService service = new DeviceFingerprintService();
DeviceFingerprint fingerprint = service.getDeviceFingerprint();
System.out.println("=== 设备信息 ===");
System.out.println("主板序列号: " + fingerprint.getMotherboardSerialNumber());
System.out.println("设备序列号: " + fingerprint.getDeviceSerialNumber());
System.out.println("CPU型号: " + fingerprint.getCpuModel());
System.out.println("CPU序列号: " + fingerprint.getCpuSerialNumber());
System.out.println("内存大小: " + fingerprint.getMemorySize());
System.out.println("首块网卡MAC地址: " + fingerprint.getFirstNetworkMacAddress());
System.out.println("硬盘序列号: " + fingerprint.getHardDiskSerialNumber());
}
public static String buildPlainText(DeviceFingerprint fingerprint) {
return fingerprint.getMotherboardSerialNumber() +
fingerprint.getDeviceSerialNumber() +
fingerprint.getCpuModel() +
fingerprint.getCpuSerialNumber() +
fingerprint.getMemorySize() +
fingerprint.getFirstNetworkMacAddress() +
fingerprint.getHardDiskSerialNumber();
}
private static void generateFingerprint() throws Exception {
DeviceFingerprintService service = new DeviceFingerprintService();
DeviceFingerprint fingerprint = service.getDeviceFingerprint();
System.out.println("=== 设备指纹信息 ===");
System.out.println("主板序列号: " + fingerprint.getMotherboardSerialNumber());
System.out.println("设备序列号: " + fingerprint.getDeviceSerialNumber());
System.out.println("CPU型号: " + fingerprint.getCpuModel());
System.out.println("CPU序列号: " + fingerprint.getCpuSerialNumber());
System.out.println("内存大小: " + fingerprint.getMemorySize());
System.out.println("首块网卡MAC地址: " + fingerprint.getFirstNetworkMacAddress());
System.out.println("硬盘序列号: " + fingerprint.getHardDiskSerialNumber());
String plainText = buildPlainText(fingerprint);
System.out.println("\n拼接后的原文: " + plainText);
byte[] signature = SM2Util.sign(plainText.getBytes(StandardCharsets.UTF_8), FINGERPRINT_PRIVATE_KEY_PATH);
System.out.println("签名结果(Base64): " + Base64.getEncoder().encodeToString(signature));
PublicKey publicKey = SM2Util.loadPublicKey(FINGERPRINT_PUBLIC_KEY_PATH);
String publicKeyPEM = SM2Util.publicKeyToPEM(publicKey);
SM3Util.writeFile(SIGN_FILE, signature);
System.out.println("签名文件已保存: " + SIGN_FILE);
String signSm3 = SM3Util.sm3DigestHex(signature);
SM3Util.writeFile(SIGN_SM3_FILE, signSm3);
System.out.println("签名SM3校验值已保存: " + SIGN_SM3_FILE + " (" + signSm3 + ")");
SM3Util.writeFile(PUBLIC_KEY_FILE, publicKeyPEM);
System.out.println("公钥文件已保存: " + PUBLIC_KEY_FILE);
String publicKeySm3 = SM3Util.sm3DigestHex(publicKeyPEM.getBytes(StandardCharsets.UTF_8));
SM3Util.writeFile(PUBLIC_KEY_SM3_FILE, publicKeySm3);
System.out.println("公钥SM3校验值已保存: " + PUBLIC_KEY_SM3_FILE + " (" + publicKeySm3 + ")");
SM3Util.writeFile(FINGERPRINT_DATA_FILE, plainText);
System.out.println("设备指纹数据已保存: " + FINGERPRINT_DATA_FILE);
boolean verified = SM2Util.verify(plainText.getBytes(StandardCharsets.UTF_8), signature, publicKey);
System.out.println("\n签名验证结果: " + verified);
}
private static void verifyFingerprint() throws Exception {
DeviceFingerprintService service = new DeviceFingerprintService();
DeviceFingerprint fingerprint = service.getDeviceFingerprint();
System.out.println("=== 当前设备信息 ===");
System.out.println("主板序列号: " + fingerprint.getMotherboardSerialNumber());
System.out.println("设备序列号: " + fingerprint.getDeviceSerialNumber());
System.out.println("CPU型号: " + fingerprint.getCpuModel());
System.out.println("CPU序列号: " + fingerprint.getCpuSerialNumber());
System.out.println("内存大小: " + fingerprint.getMemorySize());
System.out.println("首块网卡MAC地址: " + fingerprint.getFirstNetworkMacAddress());
System.out.println("硬盘序列号: " + fingerprint.getHardDiskSerialNumber());
String plainText = buildPlainText(fingerprint);
// System.out.println("\n当前拼接原文: " + plainText);
byte[] signature = SM3Util.readFileBytes(SIGN_FILE);
PublicKey publicKey = SM2Util.loadPublicKey(FINGERPRINT_PUBLIC_KEY_PATH);
boolean signatureVerified = SM2Util.verify(plainText.getBytes(StandardCharsets.UTF_8), signature, publicKey);
System.out.println("\n=== 验证结果 ===");
System.out.println("签名验证: " + signatureVerified);
if( Files.exists( Paths.get(FINGERPRINT_DATA_FILE)) ) {
String savedPlainText = SM3Util.readFile(FINGERPRINT_DATA_FILE).trim();
// System.out.println("保存的拼接原文: " + savedPlainText);
boolean dataMatch = plainText.equals(savedPlainText);
System.out.println("设备信息与保存的信息匹配: " + dataMatch);
}
// System.out.println("总体验证: " + (dataMatch && signatureVerified));
}
private static void generateMAC() throws Exception {
System.out.println("=== 生成系统文件MAC校验值 ===");
System.out.println("目标路径:");
for (String target : MAC_TARGETS) {
System.out.println(" " + target);
}
Map<String, String> sm3Map = new java.util.LinkedHashMap<>();
for (String target : MAC_TARGETS) {
File file = new File(target);
if (!file.exists()) {
System.out.println("警告: 路径不存在 - " + target);
continue;
}
if (file.isFile()) {
String sm3Value = SM3Util.sm3FileHex(target);
sm3Map.put(target, sm3Value);
System.out.println("文件: " + target + " -> " + sm3Value);
} else if (file.isDirectory()) {
Map<String, String> dirSm3Map = SM3Util.calculateDirectorySM3(target);
for (Map.Entry<String, String> entry : dirSm3Map.entrySet()) {
String absolutePath = target + "/" + entry.getKey();
sm3Map.put(absolutePath, entry.getValue());
System.out.println("文件: " + absolutePath + " -> " + entry.getValue());
}
}
}
StringBuilder macListContent = new StringBuilder();
for (Map.Entry<String, String> entry : sm3Map.entrySet()) {
macListContent.append(entry.getKey()).append("|").append(entry.getValue()).append("\n");
}
SM3Util.writeFile(MAC_LIST_FILE, macListContent.toString());
System.out.println("\nMAC列表文件已保存: " + MAC_LIST_FILE);
byte[] signature = SM2Util.sign(macListContent.toString().getBytes(StandardCharsets.UTF_8), MAC_PRIVATE_KEY_PATH);
SM3Util.writeFile(MAC_SIGN_FILE, signature);
System.out.println("MAC签名文件已保存: " + MAC_SIGN_FILE);
PublicKey publicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
boolean verified = SM2Util.verify(macListContent.toString().getBytes(StandardCharsets.UTF_8), signature, publicKey);
System.out.println("\n签名验证结果: " + verified);
}
private static void verifyMAC() throws Exception {
System.out.println("=== 验证系统文件MAC校验值 ===");
PublicKey publicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
byte[] savedSignature = SM3Util.readFileBytes(MAC_SIGN_FILE);
String savedMacList = SM3Util.readFile(MAC_LIST_FILE);
boolean macListSignatureValid = SM2Util.verify(savedMacList.getBytes(StandardCharsets.UTF_8), savedSignature, publicKey);
System.out.println("MAC列表签名验证: " + (macListSignatureValid ? "通过" : "失败"));
if (!macListSignatureValid) {
System.out.println("错误: mac.list 签名验证失败,可能被篡改!");
System.out.println("\n=== 验证结果 ===");
System.out.println("完整性验证: false");
return;
}
Map<String, String> savedSm3Map = SM3Util.readSM3File(MAC_LIST_FILE);
Map<String, String> currentSm3Map = new java.util.LinkedHashMap<>();
for (String target : MAC_TARGETS) {
File file = new File(target);
if (!file.exists()) {
continue;
}
if (file.isFile()) {
String sm3Value = SM3Util.sm3FileHex(target);
currentSm3Map.put(target, sm3Value);
} else if (file.isDirectory()) {
Map<String, String> dirSm3Map = SM3Util.calculateDirectorySM3(target);
for (Map.Entry<String, String> entry : dirSm3Map.entrySet()) {
String absolutePath = target + "/" + entry.getKey();
currentSm3Map.put(absolutePath, entry.getValue());
}
}
}
boolean allMatch = true;
for (Map.Entry<String, String> entry : savedSm3Map.entrySet()) {
String filePath = entry.getKey();
String savedHash = entry.getValue();
String currentHash = currentSm3Map.get(filePath);
if (currentHash == null) {
System.out.println("文件缺失: " + filePath);
allMatch = false;
} else if (!savedHash.equals(currentHash)) {
System.out.println("文件被修改: " + filePath + " (期望: " + savedHash + ", 实际: " + currentHash + ")");
allMatch = false;
}
}
for (String filePath : currentSm3Map.keySet()) {
if (!savedSm3Map.containsKey(filePath)) {
System.out.println("新增文件: " + filePath);
allMatch = false;
}
}
System.out.println();
System.out.println("=== 验证结果 ===");
System.out.println("完整性验证: " + allMatch);
}
private static void generateRootCertMAC() throws Exception {
System.out.println("=== 生成根证书MAC签名 ===");
InputStream certInputStream = Main.class.getResourceAsStream(ROOT_CERT_FILE);
if (certInputStream == null) {
throw new IllegalArgumentException("根证书文件未找到: " + ROOT_CERT_FILE);
}
byte[] certData = readInputStream(certInputStream);
SM3Util.writeFile(ROOT_CERT_OUTPUT_FILE, certData);
System.out.println("根证书已输出: " + ROOT_CERT_OUTPUT_FILE);
byte[] signature = SM2Util.sign(certData, MAC_PRIVATE_KEY_PATH);
SM3Util.writeFile(ROOT_CERT_SIGN_FILE, signature);
System.out.println("签名文件已保存: " + ROOT_CERT_SIGN_FILE);
PublicKey macPublicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
String publicKeyPEM = SM2Util.publicKeyToPEM(macPublicKey);
SM3Util.writeFile(MAC_PUBLIC_KEY_OUTPUT_FILE, publicKeyPEM);
System.out.println("MAC公钥文件已保存: " + MAC_PUBLIC_KEY_OUTPUT_FILE);
String publicKeySm3 = SM3Util.sm3DigestHex(macPublicKey.getEncoded());
SM3Util.writeFile(MAC_PUBLIC_KEY_SM3_FILE, publicKeySm3);
System.out.println("MAC公钥SM3校验值已保存: " + MAC_PUBLIC_KEY_SM3_FILE + " (" + publicKeySm3 + ")");
boolean verified = SM2Util.verify(certData, signature, macPublicKey);
System.out.println("\n签名验证结果: " + verified);
}
private static void verifyRootCertMAC() throws Exception {
System.out.println("=== 验证根证书MAC签名 ===");
String savedPublicKeySm3 = SM3Util.readFile(MAC_PUBLIC_KEY_SM3_FILE).trim();
PublicKey publicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
String currentPublicKeySm3 = SM3Util.sm3DigestHex(publicKey.getEncoded());
boolean publicKeyValid = savedPublicKeySm3.equals(currentPublicKeySm3);
System.out.println("公钥校验值验证: " + publicKeyValid);
InputStream certInputStream = Main.class.getResourceAsStream(ROOT_CERT_FILE);
if (certInputStream == null) {
throw new IllegalArgumentException("根证书文件未找到: " + ROOT_CERT_FILE);
}
byte[] certData = readInputStream(certInputStream);
byte[] signature = SM3Util.readFileBytes(ROOT_CERT_SIGN_FILE);
boolean signatureVerified = SM2Util.verify(certData, signature, publicKey);
System.out.println("签名验证结果: " + signatureVerified);
System.out.println();
System.out.println("=== 验证结果 ===");
System.out.println("总体验证: " + (publicKeyValid && signatureVerified));
}
private static byte[] readInputStream(InputStream is) throws Exception {
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
} finally {
if (is != null) {
is.close();
}
}
}
private static void generateCMEPMAC() throws Exception {
System.out.println("=== 生成CMEP文件MAC校验值 ===");
System.out.println("目标路径:");
for (String target : CMEP_TARGETS) {
System.out.println(" " + target);
}
Map<String, String> sm3Map = new java.util.LinkedHashMap<>();
for (String target : CMEP_TARGETS) {
File file = new File(target);
if (!file.exists()) {
System.out.println("警告: 路径不存在 - " + target);
continue;
}
if (file.isFile()) {
String sm3Value = SM3Util.sm3FileHex(target);
sm3Map.put(target, sm3Value);
System.out.println("文件: " + target + " -> " + sm3Value);
}
}
StringBuilder macListContent = new StringBuilder();
for (Map.Entry<String, String> entry : sm3Map.entrySet()) {
macListContent.append(entry.getKey()).append("|").append(entry.getValue()).append("\n");
}
SM3Util.writeFile(CMEP_MAC_LIST_FILE, macListContent.toString());
System.out.println("\nCMEP MAC列表文件已保存: " + CMEP_MAC_LIST_FILE);
byte[] signature = SM2Util.sign(macListContent.toString().getBytes(StandardCharsets.UTF_8), MAC_PRIVATE_KEY_PATH);
SM3Util.writeFile(CMEP_MAC_SIGN_FILE, signature);
System.out.println("CMEP MAC签名文件已保存: " + CMEP_MAC_SIGN_FILE);
PublicKey publicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
boolean verified = SM2Util.verify(macListContent.toString().getBytes(StandardCharsets.UTF_8), signature, publicKey);
System.out.println("\n签名验证结果: " + verified);
}
private static void verifyCMEPMAC() throws Exception {
System.out.println("=== 验证CMEP文件MAC校验值 ===");
PublicKey publicKey = SM2Util.loadPublicKey(MAC_PUBLIC_KEY_PATH);
byte[] savedSignature = SM3Util.readFileBytes(CMEP_MAC_SIGN_FILE);
String savedMacList = SM3Util.readFile(CMEP_MAC_LIST_FILE);
boolean macListSignatureValid = SM2Util.verify(savedMacList.getBytes(StandardCharsets.UTF_8), savedSignature, publicKey);
System.out.println("CMEP MAC列表签名验证: " + (macListSignatureValid ? "通过" : "失败"));
if (!macListSignatureValid) {
System.out.println("错误: cmep.mac.list 签名验证失败,可能被篡改!");
System.out.println("\n=== 验证结果 ===");
System.out.println("完整性验证: false");
return;
}
Map<String, String> savedSm3Map = SM3Util.readSM3File(CMEP_MAC_LIST_FILE);
Map<String, String> currentSm3Map = new java.util.LinkedHashMap<>();
for (String target : CMEP_TARGETS) {
File file = new File(target);
if (!file.exists()) {
continue;
}
if (file.isFile()) {
String sm3Value = SM3Util.sm3FileHex(target);
currentSm3Map.put(target, sm3Value);
}
}
boolean allMatch = true;
for (Map.Entry<String, String> entry : savedSm3Map.entrySet()) {
String filePath = entry.getKey();
String savedHash = entry.getValue();
String currentHash = currentSm3Map.get(filePath);
if (currentHash == null) {
System.out.println("文件缺失: " + filePath);
allMatch = false;
} else if (!savedHash.equals(currentHash)) {
System.out.println("文件被修改: " + filePath + " (期望: " + savedHash + ", 实际: " + currentHash + ")");
allMatch = false;
}
}
for (String filePath : currentSm3Map.keySet()) {
if (!savedSm3Map.containsKey(filePath)) {
System.out.println("新增文件: " + filePath);
allMatch = false;
}
}
System.out.println();
System.out.println("=== 验证结果 ===");
System.out.println("完整性验证: " + allMatch);
}
}
@@ -0,0 +1,258 @@
package com.sunyard.cisd.device.tool;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.encoders.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
public class SM2SignedEnvelopeUtil {
private static final String PROVIDER = "BC";
private static final String CURVE_NAME = "sm2p256v1";
private static final String KEY_ALGORITHM = "EC";
private static final String SIGNATURE_ALGORITHM = "SM3withSM2";
private static final String SM4_ALGORITHM = "SM4/GCM/NoPadding";
static {
Security.addProvider(new BouncyCastleProvider());
}
public static class SM2KeyPair {
public final PrivateKey privateKey;
public final PublicKey publicKey;
public final byte[] privateKeyBytes;
public final byte[] publicKeyBytes;
public SM2KeyPair(PrivateKey privateKey, PublicKey publicKey) {
this.privateKey = privateKey;
this.publicKey = publicKey;
this.privateKeyBytes = privateKey.getEncoded();
this.publicKeyBytes = publicKey.getEncoded();
}
public String getPrivateKeyBase64() {
return Base64.getEncoder().encodeToString(privateKeyBytes);
}
public String getPublicKeyBase64() {
return Base64.getEncoder().encodeToString(publicKeyBytes);
}
public String getPrivateKeyHex() {
return Hex.toHexString(privateKeyBytes);
}
public String getPublicKeyHex() {
return Hex.toHexString(publicKeyBytes);
}
}
public static SM2KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, PROVIDER);
ECGenParameterSpec ecSpec = new ECGenParameterSpec(CURVE_NAME);
keyPairGenerator.initialize(ecSpec, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return new SM2KeyPair(keyPair.getPrivate(), keyPair.getPublic());
}
public static PrivateKey loadPrivateKey(byte[] privateKeyBytes) throws Exception {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, PROVIDER);
return keyFactory.generatePrivate(keySpec);
}
public static PublicKey loadPublicKey(byte[] publicKeyBytes) throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, PROVIDER);
return keyFactory.generatePublic(keySpec);
}
public static byte[] createSignedAndEnvelopedData(byte[] plaintext, PrivateKey signingKey, PublicKey encryptionPublicKey) throws Exception {
byte[] signature = signData(plaintext, signingKey);
ByteArrayOutputStream signedContentBaos = new ByteArrayOutputStream();
signedContentBaos.write(signature.length >> 24 & 0xFF);
signedContentBaos.write(signature.length >> 16 & 0xFF);
signedContentBaos.write(signature.length >> 8 & 0xFF);
signedContentBaos.write(signature.length & 0xFF);
signedContentBaos.write(signature);
signedContentBaos.write(plaintext);
byte[] signedContent = signedContentBaos.toByteArray();
byte[] encryptedContent = encryptData(signedContent, encryptionPublicKey);
return encryptedContent;
}
private static byte[] signData(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
private static byte[] encryptData(byte[] data, PublicKey publicKey) throws Exception {
SecureRandom random = new SecureRandom();
byte[] iv = new byte[12];
random.nextBytes(iv);
KeyGenerator keyGen = KeyGenerator.getInstance("SM4", PROVIDER);
keyGen.init(128, random);
SecretKey sm4Key = keyGen.generateKey();
Cipher sm4Cipher = Cipher.getInstance(SM4_ALGORITHM, PROVIDER);
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
sm4Cipher.init(Cipher.ENCRYPT_MODE, sm4Key, gcmSpec);
byte[] encryptedData = sm4Cipher.doFinal(data);
Cipher ecCipher = Cipher.getInstance("ECIES", PROVIDER);
ecCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedKey = ecCipher.doFinal(sm4Key.getEncoded());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] keyLenBytes = new byte[]{
(byte)(encryptedKey.length >> 8),
(byte)encryptedKey.length
};
baos.write(keyLenBytes[0]);
baos.write(keyLenBytes[1]);
baos.write(encryptedKey);
baos.write(iv);
baos.write(encryptedData);
return baos.toByteArray();
}
public static class DecryptedResult {
public final byte[] plaintext;
public final byte[] signature;
public final boolean signatureValid;
public DecryptedResult(byte[] plaintext, byte[] signature, boolean signatureValid) {
this.plaintext = plaintext;
this.signature = signature;
this.signatureValid = signatureValid;
}
}
public static DecryptedResult openAndVerifySignedEnvelopedData(byte[] envelopeData, PrivateKey decryptionKey, PublicKey signingPublicKey) throws Exception {
int offset = 0;
int encryptedKeyLen = ((envelopeData[offset] & 0xFF) << 8) | (envelopeData[offset + 1] & 0xFF);
offset += 2;
byte[] encryptedKey = new byte[encryptedKeyLen];
System.arraycopy(envelopeData, offset, encryptedKey, 0, encryptedKeyLen);
offset += encryptedKeyLen;
byte[] iv = new byte[12];
System.arraycopy(envelopeData, offset, iv, 0, 12);
offset += 12;
byte[] encryptedData = new byte[envelopeData.length - offset];
System.arraycopy(envelopeData, offset, encryptedData, 0, encryptedData.length);
Cipher ecCipher = Cipher.getInstance("ECIES", PROVIDER);
ecCipher.init(Cipher.DECRYPT_MODE, decryptionKey);
byte[] sm4KeyBytes = ecCipher.doFinal(encryptedKey);
SecretKeySpec sm4Key = new SecretKeySpec(sm4KeyBytes, "SM4");
Cipher sm4Cipher = Cipher.getInstance(SM4_ALGORITHM, PROVIDER);
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
sm4Cipher.init(Cipher.DECRYPT_MODE, sm4Key, gcmSpec);
byte[] signedContent = sm4Cipher.doFinal(encryptedData);
int signatureLength = ((signedContent[0] & 0xFF) << 24) |
((signedContent[1] & 0xFF) << 16) |
((signedContent[2] & 0xFF) << 8) |
(signedContent[3] & 0xFF);
byte[] signature = new byte[signatureLength];
byte[] plaintext = new byte[signedContent.length - 4 - signatureLength];
System.arraycopy(signedContent, 4, signature, 0, signatureLength);
System.arraycopy(signedContent, 4 + signatureLength, plaintext, 0, plaintext.length);
boolean signatureValid = verifySignature(plaintext, signature, signingPublicKey);
return new DecryptedResult(plaintext, signature, signatureValid);
}
private static boolean verifySignature(byte[] data, byte[] signature, PublicKey publicKey) throws Exception {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
}
public static String toBase64(byte[] data) {
return Base64.getEncoder().encodeToString(data);
}
public static byte[] fromBase64(String base64) {
return Base64.getDecoder().decode(base64);
}
public static String bytesToHex(byte[] data) {
return Hex.toHexString(data);
}
public static byte[] hexToBytes(String hex) {
return Hex.decode(hex);
}
public static void main(String[] args) throws Exception {
System.out.println("=== SM2 带签名数字信封测试 ===");
System.out.println();
SM2KeyPair signingKeyPair = generateKeyPair();
SM2KeyPair encryptionKeyPair = generateKeyPair();
System.out.println("签名密钥对已生成");
System.out.println("加密密钥对已生成");
System.out.println();
String testData = "这是测试数据 - Hello World! 你好世界!";
byte[] plaintext = testData.getBytes("UTF-8");
System.out.println("原文: " + testData);
System.out.println("原文长度: " + plaintext.length + " bytes");
System.out.println();
System.out.println("创建带签名的数字信封...");
byte[] envelope = createSignedAndEnvelopedData(plaintext, signingKeyPair.privateKey, encryptionKeyPair.publicKey);
System.out.println("信封已创建,长度: " + envelope.length + " bytes");
System.out.println("信封Base64: " + toBase64(envelope).substring(0, 80) + "...");
System.out.println();
System.out.println("打开并验证数字信封...");
DecryptedResult result = openAndVerifySignedEnvelopedData(envelope, encryptionKeyPair.privateKey, signingKeyPair.publicKey);
System.out.println("解密后原文: " + new String(result.plaintext, "UTF-8"));
System.out.println("签名有效: " + result.signatureValid);
System.out.println("签名: " + bytesToHex(result.signature));
System.out.println();
if (result.signatureValid) {
System.out.println("=== 验签成功 ===");
} else {
System.out.println("=== 验签失败 ===");
}
}
}
@@ -0,0 +1,134 @@
package com.sunyard.cisd.device.tool;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SM2Util {
private static final String ALGORITHM = "EC";
private static final String PROVIDER = "BC";
private static final String CURVE_NAME = "sm2p256v1";
private static final String SIGNATURE_ALGORITHM = "SM3withSM2";
static {
Security.addProvider(new BouncyCastleProvider());
}
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
public static boolean verify(byte[] data, byte[] sign, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(sign);
}
public static byte[] sign(byte[] data, String privateKeyFilePath) throws Exception {
PrivateKey privateKey = loadPrivateKey(privateKeyFilePath);
return sign(data, privateKey);
}
public static boolean verify(byte[] data, byte[] sign, String publicKeyFilePath) throws Exception {
PublicKey publicKey = loadPublicKey(publicKeyFilePath);
return verify(data, sign, publicKey);
}
public static PrivateKey loadPrivateKey(String filePath) throws Exception {
InputStream inputStream = SM2Util.class.getResourceAsStream(filePath);
if (inputStream == null) {
throw new IllegalArgumentException("Private key file not found: " + filePath);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
StringBuilder keyBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (!line.startsWith("-----")) {
keyBuilder.append(line.trim());
}
}
reader.close();
String keyBase64 = keyBuilder.toString();
byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);
return keyFactory.generatePrivate(keySpec);
}
public static PublicKey loadPublicKey(String filePath) throws Exception {
InputStream inputStream = SM2Util.class.getResourceAsStream(filePath);
if (inputStream == null) {
throw new IllegalArgumentException("Public key file not found: " + filePath);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
StringBuilder keyBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (!line.startsWith("-----")) {
keyBuilder.append(line.trim());
}
}
reader.close();
String keyBase64 = keyBuilder.toString();
byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);
return keyFactory.generatePublic(keySpec);
}
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(CURVE_NAME);
keyPairGenerator.initialize(ecSpec, new SecureRandom());
return keyPairGenerator.generateKeyPair();
}
public static String privateKeyToPEM(PrivateKey privateKey) {
byte[] encoded = privateKey.getEncoded();
String base64 = Base64.getEncoder().encodeToString(encoded);
StringBuilder pem = new StringBuilder();
pem.append("-----BEGIN PRIVATE KEY-----\n");
int index = 0;
while (index < base64.length()) {
pem.append(base64.substring(index, Math.min(index + 64, base64.length())));
pem.append("\n");
index += 64;
}
pem.append("-----END PRIVATE KEY-----\n");
return pem.toString();
}
public static String publicKeyToPEM(PublicKey publicKey) {
byte[] encoded = publicKey.getEncoded();
String base64 = Base64.getEncoder().encodeToString(encoded);
StringBuilder pem = new StringBuilder();
pem.append("-----BEGIN PUBLIC KEY-----\n");
int index = 0;
while (index < base64.length()) {
pem.append(base64.substring(index, Math.min(index + 64, base64.length())));
pem.append("\n");
index += 64;
}
pem.append("-----END PUBLIC KEY-----\n");
return pem.toString();
}
}
@@ -0,0 +1,162 @@
package com.sunyard.cisd.device.tool;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.util.encoders.Hex;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class SM3Util {
public static byte[] sm3Digest(byte[] data) {
SM3Digest digest = new SM3Digest();
digest.update(data, 0, data.length);
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
return result;
}
public static String sm3DigestHex(byte[] data) {
byte[] digest = sm3Digest(data);
return Hex.toHexString(digest);
}
public static String sm3FileHex(String filePath) throws Exception {
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
throw new IllegalArgumentException("File not found: " + filePath);
}
try (FileInputStream fis = new FileInputStream(file)) {
SM3Digest digest = new SM3Digest();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
digest.update(buffer, 0, bytesRead);
}
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
return Hex.toHexString(result);
}
}
public static Map<String, String> calculateDirectorySM3(String directoryPath) throws Exception {
File dir = new File(directoryPath);
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalArgumentException("Directory not found: " + directoryPath);
}
Map<String, String> sm3Map = new HashMap<>();
calculateDirectorySM3Recursive(dir, dir.getAbsolutePath(), sm3Map);
return sm3Map;
}
private static void calculateDirectorySM3Recursive(File dir, String basePath, Map<String, String> sm3Map) throws Exception {
File[] files = dir.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isDirectory()) {
calculateDirectorySM3Recursive(file, basePath, sm3Map);
} else {
String relativePath = file.getAbsolutePath().substring(basePath.length() + 1);
String sm3Value = sm3FileHex(file.getAbsolutePath());
sm3Map.put(relativePath, sm3Value);
}
}
}
public static void writeSM3File(Map<String, String> sm3Map, String outputFilePath) throws Exception {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sm3Map.entrySet()) {
sb.append(entry.getKey()).append("|").append(entry.getValue()).append("\n");
}
writeFile(outputFilePath, sb.toString());
}
public static Map<String, String> readSM3File(String filePath) throws Exception {
Map<String, String> sm3Map = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\|", 2);
if (parts.length == 2) {
sm3Map.put(parts[0], parts[1]);
}
}
}
return sm3Map;
}
public static boolean verifyDirectorySM3(String directoryPath, String sm3FilePath) throws Exception {
Map<String, String> savedSM3 = readSM3File(sm3FilePath);
Map<String, String> currentSM3 = calculateDirectorySM3(directoryPath);
boolean allMatch = true;
for (Map.Entry<String, String> entry : savedSM3.entrySet()) {
String filePath = entry.getKey();
String savedHash = entry.getValue();
String currentHash = currentSM3.get(filePath);
if (currentHash == null) {
System.out.println("文件缺失: " + filePath);
allMatch = false;
} else if (!savedHash.equals(currentHash)) {
System.out.println("文件校验失败: " + filePath + " (期望: " + savedHash + ", 实际: " + currentHash + ")");
allMatch = false;
}
}
for (String filePath : currentSM3.keySet()) {
if (!savedSM3.containsKey(filePath)) {
System.out.println("新增文件: " + filePath);
allMatch = false;
}
}
return allMatch;
}
public static void writeFile(String filePath, byte[] content) throws Exception {
File file = new File(filePath);
File parentDir = file.getParentFile();
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs();
}
try (OutputStream os = new FileOutputStream(file)) {
os.write(content);
}
}
public static void writeFile(String filePath, String content) throws Exception {
writeFile(filePath, content.getBytes(StandardCharsets.UTF_8));
}
public static String readFile(String filePath) throws Exception {
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString();
}
public static byte[] readFileBytes(String filePath) throws Exception {
File file = new File(filePath);
try (FileInputStream fis = new FileInputStream(file)) {
byte[] content = new byte[(int) file.length()];
fis.read(content);
return content;
}
}
}
@@ -0,0 +1,33 @@
package com.sunyard.cisd.device.tool;
import com.sun.jna.Structure;
import lombok.Data;
@Data
@Structure.FieldOrder({
"issuerName",
"deviceName",
"deviceSerial",
"deviceVersion",
"standardVersion",
"asymAlgAbility",
"symAlgAbility",
"hashAlgAbility",
"bufferSize"
})
public class SdfDeviceInfo extends Structure {
public byte[] issuerName = new byte[40];
public byte[] deviceName = new byte[16];
public byte[] deviceSerial = new byte[16];
public int deviceVersion;
public int standardVersion;
public int[] asymAlgAbility = new int[2];
public int symAlgAbility;
public int hashAlgAbility;
public int bufferSize;
public SdfDeviceInfo() {
super(ALIGN_NONE);
}
}
@@ -0,0 +1,13 @@
package com.sunyard.cisd.device.tool;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
public interface SdfNativeLibrary extends Library {
int SDF_OpenDevice(PointerByReference phDeviceHandle);
int SDF_CloseDevice(Pointer hDeviceHandle);
int SDF_OpenSession(Pointer hDeviceHandle, PointerByReference phSessionHandle);
int SDF_CloseSession(Pointer hSessionHandle);
int SDF_GetDeviceInfo(Pointer hSessionHandle, SdfDeviceInfo deviceInfo);
}
Binary file not shown.
@@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgyJA6u1jwC/MP+/K7
ntiVLFB0XsldCIdY8Lift06UEaugCgYIKoEcz1UBgi2hRANCAAR7x0q/Bqj6JVwR
mfjccNmJ5Wd8ZuDZZnPudWT1UupNtg9aNaEYHYa52xANhiu3IzOELmTtfs/QRMRe
oabBvDAi
-----END PRIVATE KEY-----
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEe8dKvwao+iVcEZn43HDZieVnfGbg
2WZz7nVk9VLqTbYPWjWhGB2GudsQDYYrtyMzhC5k7X7P0ETEXqGmwbwwIg==
-----END PUBLIC KEY-----
@@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgh9tzISMZY6ob2KVM
0Am9+Zm2jG+CLhp+g72hN3t7dl2gCgYIKoEcz1UBgi2hRANCAAT+73yu5EIYMSjc
60mEZXmYpR2O8yTWOY4WmG1eZqKhB/46DarhZVN8AAvpOYohZ1l3luk26jnpQNYx
psC8QVu5
-----END PRIVATE KEY-----
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE/u98ruRCGDEo3OtJhGV5mKUdjvMk
1jmOFphtXmaioQf+Og2q4WVTfAAL6TmKIWdZd5bpNuo56UDWMabAvEFbuQ==
-----END PUBLIC KEY-----
@@ -0,0 +1,51 @@
package com.sunyard.cisd;
import com.sunyard.cisd.device.tool.CMSUtil;
import com.sunyard.cisd.device.tool.SM3Util;
public class CMSSignatureTest {
public static void main(String[] args) {
try {
System.out.println("=== CMS 签名验签测试 ===");
System.out.println();
String cbcCmsData = SM3Util.readFile("d:/workbench/sectool/cbc.cms").trim();
String icbcCmsData = SM3Util.readFile("d:/workbench/sectool/icbc.cms").trim();
System.out.println("--- 验证 cbc.cms ---");
String cbcType = CMSUtil.detectCMSType(cbcCmsData);
System.out.println("cbc.cms CMS类型: " + cbcType);
boolean cbcVerified = false;
if ("SignedData".equals(cbcType)) {
cbcVerified = CMSUtil.verifySignedData(cbcCmsData);
System.out.println("cbc.cms 验签结果: " + (cbcVerified ? "成功" : "失败"));
} else if ("SignedAndEnvelopedData".equals(cbcType)) {
System.out.println("cbc.cms 是SignedAndEnvelopedData类型(同时签名和加密)");
System.out.println("需要使用对应的私钥解密后才能验证签名");
}
System.out.println();
System.out.println("--- 验证 icbc.cms ---");
String icbcType = CMSUtil.detectCMSType(icbcCmsData);
System.out.println("icbc.cms CMS类型: " + icbcType);
boolean icbcVerified = false;
if ("SignedData".equals(icbcType)) {
icbcVerified = CMSUtil.verifySignedData(icbcCmsData);
System.out.println("icbc.cms 验签结果: " + (icbcVerified ? "成功" : "失败"));
} else if ("SignedAndEnvelopedData".equals(icbcType)) {
System.out.println("icbc.cms 是SignedAndEnvelopedData类型(同时签名和加密)");
System.out.println("需要使用对应的私钥解密后才能验证签名");
}
System.out.println();
System.out.println("=== 测试完成 ===");
} catch (Exception e) {
System.err.println("测试失败: " + e.getMessage());
e.printStackTrace();
}
}
}
@@ -0,0 +1,103 @@
package com.sunyard.cisd;
import com.sunyard.cisd.device.tool.SM2Util;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
public class SM2UtilTest {
private static final String KEY_NAME_FINGERPRINT = "fingerprint";
private static final String KEY_NAME_MAC = "mac";
@Test
public void testGenerateAndSaveKeyPairs() throws Exception {
KeyPair fingerprintKeyPair = SM2Util.generateKeyPair();
KeyPair macKeyPair = SM2Util.generateKeyPair();
String resourcesPath = "src/main/resources";
File resourcesDir = new File(resourcesPath);
if (!resourcesDir.exists()) {
resourcesDir.mkdirs();
}
File fingerprintPrivateKeyFile = new File(resourcesPath + "/sm2_" + KEY_NAME_FINGERPRINT + "_private_key.pem");
try (Writer writer = new OutputStreamWriter(new FileOutputStream(fingerprintPrivateKeyFile), StandardCharsets.UTF_8)) {
writer.write(SM2Util.privateKeyToPEM(fingerprintKeyPair.getPrivate()));
}
System.out.println("Fingerprint private key saved to: " + fingerprintPrivateKeyFile.getAbsolutePath());
File fingerprintPublicKeyFile = new File(resourcesPath + "/sm2_" + KEY_NAME_FINGERPRINT + "_public_key.pem");
try (Writer writer = new OutputStreamWriter(new FileOutputStream(fingerprintPublicKeyFile), StandardCharsets.UTF_8)) {
writer.write(SM2Util.publicKeyToPEM(fingerprintKeyPair.getPublic()));
}
System.out.println("Fingerprint public key saved to: " + fingerprintPublicKeyFile.getAbsolutePath());
File macPrivateKeyFile = new File(resourcesPath + "/sm2_" + KEY_NAME_MAC + "_private_key.pem");
try (Writer writer = new OutputStreamWriter(new FileOutputStream(macPrivateKeyFile), StandardCharsets.UTF_8)) {
writer.write(SM2Util.privateKeyToPEM(macKeyPair.getPrivate()));
}
System.out.println("MAC private key saved to: " + macPrivateKeyFile.getAbsolutePath());
File macPublicKeyFile = new File(resourcesPath + "/sm2_" + KEY_NAME_MAC + "_public_key.pem");
try (Writer writer = new OutputStreamWriter(new FileOutputStream(macPublicKeyFile), StandardCharsets.UTF_8)) {
writer.write(SM2Util.publicKeyToPEM(macKeyPair.getPublic()));
}
System.out.println("MAC public key saved to: " + macPublicKeyFile.getAbsolutePath());
System.out.println("\n=== Generated Fingerprint Key Pair ===");
System.out.println("Private Key:\n" + SM2Util.privateKeyToPEM(fingerprintKeyPair.getPrivate()));
System.out.println("Public Key:\n" + SM2Util.publicKeyToPEM(fingerprintKeyPair.getPublic()));
System.out.println("\n=== Generated MAC Key Pair ===");
System.out.println("Private Key:\n" + SM2Util.privateKeyToPEM(macKeyPair.getPrivate()));
System.out.println("Public Key:\n" + SM2Util.publicKeyToPEM(macKeyPair.getPublic()));
}
@Test
public void testSignAndVerify() throws Exception {
KeyPair keyPair = SM2Util.generateKeyPair();
String testData = "Hello, SM2!";
byte[] data = testData.getBytes(StandardCharsets.UTF_8);
byte[] signature = SM2Util.sign(data, keyPair.getPrivate());
System.out.println("Signature generated, length: " + signature.length + " bytes");
boolean verified = SM2Util.verify(data, signature, keyPair.getPublic());
System.out.println("Signature verified: " + verified);
assert verified : "Signature verification failed";
}
@Test
public void testSignAndVerifyWithKeyFiles() throws Exception {
testGenerateAndSaveKeyPairs();
String testData = "Test data for SM2 signature";
byte[] data = testData.getBytes(StandardCharsets.UTF_8);
byte[] fingerprintSignature = SM2Util.sign(data, "/sm2_fingerprint_private_key.pem");
System.out.println("Fingerprint signature generated, length: " + fingerprintSignature.length + " bytes");
boolean fingerprintVerified = SM2Util.verify(data, fingerprintSignature, "/sm2_fingerprint_public_key.pem");
System.out.println("Fingerprint signature verified: " + fingerprintVerified);
assert fingerprintVerified : "Fingerprint signature verification failed";
byte[] macSignature = SM2Util.sign(data, "/sm2_mac_private_key.pem");
System.out.println("MAC signature generated, length: " + macSignature.length + " bytes");
boolean macVerified = SM2Util.verify(data, macSignature, "/sm2_mac_public_key.pem");
System.out.println("MAC signature verified: " + macVerified);
assert macVerified : "MAC signature verification failed";
boolean crossVerified = SM2Util.verify(data, fingerprintSignature, "/sm2_mac_public_key.pem");
System.out.println("Cross verification (fingerprint signature with MAC key): " + crossVerified);
assert !crossVerified : "Cross verification should fail";
}
}