init
This commit is contained in:
+26
@@ -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
|
||||
@@ -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=
|
||||
@@ -0,0 +1 @@
|
||||
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
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user