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.RestController;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.util.Base64;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/device")
|
||||
public class DeviceActivationController {
|
||||
@ -24,8 +27,10 @@ public class DeviceActivationController {
|
||||
String concatenatedParams = params.toConcatenatedString();
|
||||
String calculatedHash = deviceActivationService.calculateSm3Hash(concatenatedParams);
|
||||
|
||||
String deviceActivationPublicKey = deviceActivationService.generateDeviceActivationPublicKey();
|
||||
String deviceActivationResult = deviceActivationService.signWithSm2Pkcs1(calculatedHash, deviceActivationPublicKey);
|
||||
KeyPair keyPair = deviceActivationService.generateDeviceActivationKeyPair();
|
||||
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();
|
||||
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() {
|
||||
try {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", PROVIDER);
|
||||
|
||||
@ -18,6 +18,33 @@
|
||||
</properties>
|
||||
|
||||
<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>
|
||||
|
||||
<build>
|
||||
@ -44,6 +71,30 @@
|
||||
</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.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>
|
||||
@ -1,9 +1,45 @@
|
||||
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.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();
|
||||
@ -43,65 +79,148 @@ public class DeviceFingerprintService {
|
||||
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() {
|
||||
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";
|
||||
}
|
||||
|
||||
int hDevice = -1;
|
||||
int hSession = -1;
|
||||
Pointer deviceHandle = null;
|
||||
Pointer sessionHandle = null;
|
||||
|
||||
try {
|
||||
byte[] deviceName = new byte[256];
|
||||
int[] deviceNameLen = new int[]{256};
|
||||
int ret = SDFNative.SDF_OpenDevice(0, deviceName, deviceNameLen);
|
||||
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("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";
|
||||
}
|
||||
hDevice = ret;
|
||||
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);
|
||||
|
||||
byte[] appID = "DeviceFingerprint".getBytes();
|
||||
int[] sessionHandle = new int[1];
|
||||
ret = SDFNative.SDF_OpenSession(hDevice, 0, appID, appID.length, sessionHandle);
|
||||
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";
|
||||
}
|
||||
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();
|
||||
ret = SDFNative.SDF_GetDeviceInfo(hSession, info);
|
||||
ret = sdfLibrary.SDF_GetDeviceInfo(sessionHandle, info);
|
||||
System.out.println("[DEBUG] SDF_GetDeviceInfo returned: " + ret);
|
||||
|
||||
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";
|
||||
}
|
||||
info.read();
|
||||
|
||||
String deviceSerial = info.getDeviceSerial();
|
||||
return deviceSerial.isEmpty() ? "Unknown" : deviceSerial;
|
||||
String issuerName = zeroTerminatedString(info.getIssuerName());
|
||||
String deviceName = zeroTerminatedString(info.getDeviceName());
|
||||
String deviceSerial = zeroTerminatedString(info.getDeviceSerial());
|
||||
|
||||
} catch (UnsatisfiedLinkError | Exception e) {
|
||||
System.err.println("Failed to get device serial number from SDF: " + e.getMessage());
|
||||
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 (hSession != -1) {
|
||||
if (sessionHandle != null) {
|
||||
try {
|
||||
SDFNative.SDF_CloseSession(hSession);
|
||||
System.out.println("[DEBUG] Closing session handle: " + sessionHandle);
|
||||
sdfLibrary.SDF_CloseSession(sessionHandle);
|
||||
} 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 {
|
||||
SDFNative.SDF_CloseDevice(hDevice);
|
||||
System.out.println("[DEBUG] Closing device handle: " + deviceHandle);
|
||||
sdfLibrary.SDF_CloseDevice(deviceHandle);
|
||||
} 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) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
|
||||
@ -124,11 +243,11 @@ public class DeviceFingerprintService {
|
||||
String result = output.toString().trim();
|
||||
return result.isEmpty() ? "Unknown" : result;
|
||||
} 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";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error executing command '" + command + "': " + e.getMessage());
|
||||
System.err.println("[ERROR] Error executing command '" + command + "': " + e.getMessage());
|
||||
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;
|
||||
|
||||
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[] deviceName = new byte[40];
|
||||
public byte[] deviceSerial = 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[] asymAlgAbility = new int[2];
|
||||
public int symAlgAbility;
|
||||
public int hashAlgAbility;
|
||||
public int bufferSize;
|
||||
|
||||
public void read() {
|
||||
}
|
||||
|
||||
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();
|
||||
public SdfDeviceInfo() {
|
||||
super(ALIGN_NONE);
|
||||
}
|
||||
}
|
||||
@ -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