SM2 版本工具
This commit is contained in:
parent
3779a055e0
commit
fc273376a7
@ -6,6 +6,9 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/device")
|
@RequestMapping("/device")
|
||||||
public class DeviceActivationController {
|
public class DeviceActivationController {
|
||||||
@ -24,8 +27,10 @@ public class DeviceActivationController {
|
|||||||
String concatenatedParams = params.toConcatenatedString();
|
String concatenatedParams = params.toConcatenatedString();
|
||||||
String calculatedHash = deviceActivationService.calculateSm3Hash(concatenatedParams);
|
String calculatedHash = deviceActivationService.calculateSm3Hash(concatenatedParams);
|
||||||
|
|
||||||
String deviceActivationPublicKey = deviceActivationService.generateDeviceActivationPublicKey();
|
KeyPair keyPair = deviceActivationService.generateDeviceActivationKeyPair();
|
||||||
String deviceActivationResult = deviceActivationService.signWithSm2Pkcs1(calculatedHash, deviceActivationPublicKey);
|
String deviceActivationPublicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
|
||||||
|
String privateKeyBase64 = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
|
||||||
|
String deviceActivationResult = deviceActivationService.signWithSm2Pkcs1(calculatedHash, privateKeyBase64);
|
||||||
|
|
||||||
DeviceActivationResponse.Data data = new DeviceActivationResponse.Data();
|
DeviceActivationResponse.Data data = new DeviceActivationResponse.Data();
|
||||||
data.setHash(calculatedHash);
|
data.setHash(calculatedHash);
|
||||||
|
|||||||
@ -63,6 +63,16 @@ public class DeviceActivationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeyPair generateDeviceActivationKeyPair() {
|
||||||
|
try {
|
||||||
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", PROVIDER);
|
||||||
|
keyGen.initialize(256);
|
||||||
|
return keyGen.generateKeyPair();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("生成设备激活密钥对失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public KeyPair generateKeyPair() {
|
public KeyPair generateKeyPair() {
|
||||||
try {
|
try {
|
||||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", PROVIDER);
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", PROVIDER);
|
||||||
|
|||||||
@ -18,6 +18,33 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<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>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -44,6 +71,30 @@
|
|||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@ -1,9 +1,45 @@
|
|||||||
package com.sunyard.cisd;
|
package com.sunyard.cisd;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class DeviceFingerprintService {
|
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() {
|
public DeviceFingerprint getDeviceFingerprint() {
|
||||||
DeviceFingerprint fingerprint = new DeviceFingerprint();
|
DeviceFingerprint fingerprint = new DeviceFingerprint();
|
||||||
@ -43,65 +79,148 @@ public class DeviceFingerprintService {
|
|||||||
return result != null && !result.isEmpty() ? result : "Unknown";
|
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() {
|
private String getDeviceSerialNumber() {
|
||||||
if (!SDFNative.isLibraryLoaded()) {
|
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";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
int hDevice = -1;
|
Pointer deviceHandle = null;
|
||||||
int hSession = -1;
|
Pointer sessionHandle = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] deviceName = new byte[256];
|
System.out.println("[DEBUG] Calling SDF_OpenDevice...");
|
||||||
int[] deviceNameLen = new int[]{256};
|
PointerByReference phDeviceHandle = new PointerByReference();
|
||||||
int ret = SDFNative.SDF_OpenDevice(0, deviceName, deviceNameLen);
|
int ret = sdfLibrary.SDF_OpenDevice(phDeviceHandle);
|
||||||
|
System.out.println("[DEBUG] SDF_OpenDevice returned: " + ret);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
System.err.println("SDF_OpenDevice failed with error: " + ret);
|
System.err.println("[ERROR] SDF_OpenDevice failed with error code: " + ret);
|
||||||
|
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
hDevice = ret;
|
deviceHandle = phDeviceHandle.getValue();
|
||||||
|
System.out.println("[DEBUG] Device handle obtained: " + deviceHandle);
|
||||||
|
|
||||||
byte[] appID = "DeviceFingerprint".getBytes();
|
System.out.println("[DEBUG] Calling SDF_OpenSession...");
|
||||||
int[] sessionHandle = new int[1];
|
PointerByReference phSessionHandle = new PointerByReference();
|
||||||
ret = SDFNative.SDF_OpenSession(hDevice, 0, appID, appID.length, sessionHandle);
|
ret = sdfLibrary.SDF_OpenSession(deviceHandle, phSessionHandle);
|
||||||
|
System.out.println("[DEBUG] SDF_OpenSession returned: " + ret);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
System.err.println("SDF_OpenSession failed with error: " + ret);
|
System.err.println("[ERROR] SDF_OpenSession failed with error code: " + ret);
|
||||||
|
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
hSession = sessionHandle[0];
|
sessionHandle = phSessionHandle.getValue();
|
||||||
|
System.out.println("[DEBUG] Session handle obtained: " + sessionHandle);
|
||||||
|
|
||||||
|
System.out.println("[DEBUG] Calling SDF_GetDeviceInfo...");
|
||||||
SdfDeviceInfo info = new SdfDeviceInfo();
|
SdfDeviceInfo info = new SdfDeviceInfo();
|
||||||
ret = SDFNative.SDF_GetDeviceInfo(hSession, info);
|
ret = sdfLibrary.SDF_GetDeviceInfo(sessionHandle, info);
|
||||||
|
System.out.println("[DEBUG] SDF_GetDeviceInfo returned: " + ret);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
System.err.println("SDF_GetDeviceInfo failed with error: " + ret);
|
System.err.println("[ERROR] SDF_GetDeviceInfo failed with error code: " + ret);
|
||||||
|
System.err.println("[ERROR] Error code meaning: " + getErrorMessage(ret));
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
info.read();
|
|
||||||
|
|
||||||
String deviceSerial = info.getDeviceSerial();
|
String issuerName = zeroTerminatedString(info.getIssuerName());
|
||||||
return deviceSerial.isEmpty() ? "Unknown" : deviceSerial;
|
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 + "'");
|
||||||
|
|
||||||
} catch (UnsatisfiedLinkError | Exception e) {
|
if (deviceSerial == null || deviceSerial.isEmpty()) {
|
||||||
System.err.println("Failed to get device serial number from SDF: " + e.getMessage());
|
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";
|
return "Unknown";
|
||||||
} finally {
|
} finally {
|
||||||
if (hSession != -1) {
|
if (sessionHandle != null) {
|
||||||
try {
|
try {
|
||||||
SDFNative.SDF_CloseSession(hSession);
|
System.out.println("[DEBUG] Closing session handle: " + sessionHandle);
|
||||||
|
sdfLibrary.SDF_CloseSession(sessionHandle);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Error closing session: " + e.getMessage());
|
System.err.println("[ERROR] Error closing session: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hDevice != -1) {
|
if (deviceHandle != null) {
|
||||||
try {
|
try {
|
||||||
SDFNative.SDF_CloseDevice(hDevice);
|
System.out.println("[DEBUG] Closing device handle: " + deviceHandle);
|
||||||
|
sdfLibrary.SDF_CloseDevice(deviceHandle);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Error closing device: " + e.getMessage());
|
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) {
|
private String executeCommand(String command) {
|
||||||
try {
|
try {
|
||||||
Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
|
Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
|
||||||
@ -124,11 +243,11 @@ public class DeviceFingerprintService {
|
|||||||
String result = output.toString().trim();
|
String result = output.toString().trim();
|
||||||
return result.isEmpty() ? "Unknown" : result;
|
return result.isEmpty() ? "Unknown" : result;
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Command '" + command + "' failed with exit code " + exitCode + ": " + errorOutput);
|
System.err.println("[ERROR] Command '" + command + "' failed with exit code " + exitCode + ": " + errorOutput);
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("Error executing command '" + command + "': " + e.getMessage());
|
System.err.println("[ERROR] Error executing command '" + command + "': " + e.getMessage());
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
package com.sunyard.cisd;
|
|
||||||
|
|
||||||
public class SDFNative {
|
|
||||||
private static final String SDF_LIBRARY_PATH = "/home/tms/libs/libsdf_syd1408-x64.so.1.0.0";
|
|
||||||
private static boolean libraryLoaded = false;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
System.load(SDF_LIBRARY_PATH);
|
|
||||||
libraryLoaded = true;
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
|
||||||
System.err.println("Warning: SDF library not loaded: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLibraryLoaded() {
|
|
||||||
return libraryLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static native int SDF_OpenDevice(int dwDeviceType, byte[] pDeviceName, int[] pdwDeviceNameLen);
|
|
||||||
public static native int SDF_CloseDevice(int hDevice);
|
|
||||||
public static native int SDF_OpenSession(int hDevice, int dwAppType, byte[] pAppID, int dwAppIDLen, int[] phSession);
|
|
||||||
public static native int SDF_CloseSession(int hSession);
|
|
||||||
public static native int SDF_GetDeviceInfo(int hSession, SdfDeviceInfo pDeviceInfo);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,156 @@
|
|||||||
|
package com.sunyard.cisd;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
|
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
|
||||||
|
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.crypto.engines.SM2Engine;
|
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
||||||
|
import org.bouncycastle.crypto.signers.SM2Signer;
|
||||||
|
import org.bouncycastle.jce.ECNamedCurveTable;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.bouncycastle.util.BigIntegers;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.security.Signature;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,41 +1,36 @@
|
|||||||
package com.sunyard.cisd;
|
package com.sunyard.cisd;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import com.sun.jna.Structure;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Structure.FieldOrder({
|
||||||
|
"issuerName",
|
||||||
|
"deviceName",
|
||||||
|
"deviceSerial",
|
||||||
|
"deviceVersion",
|
||||||
|
"standardVersion",
|
||||||
|
"asymAlgAbility",
|
||||||
|
"symAlgAbility",
|
||||||
|
"hashAlgAbility",
|
||||||
|
"bufferSize"
|
||||||
|
})
|
||||||
|
public class SdfDeviceInfo extends Structure {
|
||||||
|
|
||||||
public class SdfDeviceInfo {
|
|
||||||
public byte[] issuerName = new byte[40];
|
public byte[] issuerName = new byte[40];
|
||||||
public byte[] deviceName = new byte[40];
|
public byte[] deviceName = new byte[16];
|
||||||
public byte[] deviceSerial = new byte[40];
|
public byte[] deviceSerial = new byte[16];
|
||||||
public int deviceVersion;
|
public int deviceVersion;
|
||||||
public int standardVersion;
|
public int standardVersion;
|
||||||
public int asymAlgAbility[] = new int[2];
|
public int[] asymAlgAbility = new int[2];
|
||||||
public int symAlgAbility;
|
public int symAlgAbility;
|
||||||
public int hashAlgAbility;
|
public int hashAlgAbility;
|
||||||
public int bufferSize;
|
public int bufferSize;
|
||||||
|
|
||||||
public void read() {
|
public SdfDeviceInfo() {
|
||||||
}
|
super(ALIGN_NONE);
|
||||||
|
|
||||||
public String getIssuerName() {
|
|
||||||
return zeroTerminatedString(issuerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceName() {
|
|
||||||
return zeroTerminatedString(deviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceSerial() {
|
|
||||||
return zeroTerminatedString(deviceSerial);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String zeroTerminatedString(byte[] bytes) {
|
|
||||||
if (bytes == null || bytes.length == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
int len = 0;
|
|
||||||
while (len < bytes.length && bytes[len] != 0) {
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
return new String(bytes, 0, len).trim();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.sunyard.cisd;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg7isDlcvx8WmYYw/6
|
||||||
|
Xc25GcgDx3N19Czq6O2tz2v5Jx+gCgYIKoEcz1UBgi2hRANCAATJMA+gouZuIttR
|
||||||
|
bqpDk/tjk4jefTgG1ncg7xuVoTVz10hFja5bbTssru4oD4Pooxz4VbTR1KIylDYo
|
||||||
|
bLe3PyUJ
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyTAPoKLmbiLbUW6qQ5P7Y5OI3n04
|
||||||
|
BtZ3IO8blaE1c9dIRY2uW207LK7uKA+D6KMc+FW00dSiMpQ2KGy3tz8lCQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.sunyard.cisd;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenerateAndSaveKeyPair() throws Exception {
|
||||||
|
KeyPair keyPair = SM2Util.generateKeyPair();
|
||||||
|
|
||||||
|
String privateKeyPEM = SM2Util.privateKeyToPEM(keyPair.getPrivate());
|
||||||
|
String publicKeyPEM = SM2Util.publicKeyToPEM(keyPair.getPublic());
|
||||||
|
|
||||||
|
String resourcesPath = "src/main/resources";
|
||||||
|
File resourcesDir = new File(resourcesPath);
|
||||||
|
if (!resourcesDir.exists()) {
|
||||||
|
resourcesDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File privateKeyFile = new File(resourcesPath + "/sm2_private_key.pem");
|
||||||
|
try (Writer writer = new OutputStreamWriter(new FileOutputStream(privateKeyFile), StandardCharsets.UTF_8)) {
|
||||||
|
writer.write(privateKeyPEM);
|
||||||
|
}
|
||||||
|
System.out.println("Private key saved to: " + privateKeyFile.getAbsolutePath());
|
||||||
|
|
||||||
|
File publicKeyFile = new File(resourcesPath + "/sm2_public_key.pem");
|
||||||
|
try (Writer writer = new OutputStreamWriter(new FileOutputStream(publicKeyFile), StandardCharsets.UTF_8)) {
|
||||||
|
writer.write(publicKeyPEM);
|
||||||
|
}
|
||||||
|
System.out.println("Public key saved to: " + publicKeyFile.getAbsolutePath());
|
||||||
|
|
||||||
|
System.out.println("\nGenerated Key Pair:");
|
||||||
|
System.out.println("Private Key:\n" + privateKeyPEM);
|
||||||
|
System.out.println("Public Key:\n" + publicKeyPEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 {
|
||||||
|
testGenerateAndSaveKeyPair();
|
||||||
|
|
||||||
|
String testData = "Test data for SM2 signature";
|
||||||
|
byte[] data = testData.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
byte[] signature = SM2Util.sign(data, "/sm2_private_key.pem");
|
||||||
|
System.out.println("Signature generated from file, length: " + signature.length + " bytes");
|
||||||
|
|
||||||
|
boolean verified = SM2Util.verify(data, signature, "/sm2_public_key.pem");
|
||||||
|
System.out.println("Signature verified from file: " + verified);
|
||||||
|
|
||||||
|
assert verified : "Signature verification with key files failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user