瀏覽代碼

集成签名模块

sakuya 3 年之前
父節點
當前提交
05a6361887

+ 84 - 0
eladmin-sign/pom.xml

@@ -0,0 +1,84 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>eladmin</artifactId>
+        <groupId>me.zhengjie</groupId>
+        <version>2.6</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>eladmin-sign</artifactId>
+    <name>签名模块</name>
+
+    <properties>
+        <jackson.version>2.11.1</jackson.version>
+        <dateformat.version>2.6.7</dateformat.version>
+        <cfca.common.version>3.7.5.3</cfca.common.version>
+        <cfca.sadk.version>3.7.1.0</cfca.sadk.version>
+        <cfca.logback.version>4.2.1.0</cfca.logback.version>
+        <cfca.paperless.version>3.0.2.1</cfca.paperless.version>
+        <cfca.SealSADK7.version>5.8.2.1</cfca.SealSADK7.version>
+        <cfca.SealSADK.version>3.1.4.0</cfca.SealSADK.version>
+        <cfca.timestampAPI.version>4.2.2.0</cfca.timestampAPI.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-cbor</artifactId>
+            <version>${dateformat.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.trustsign</groupId>
+            <artifactId>common</artifactId>
+            <version>${cfca.common.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>sadk</artifactId>
+            <version>${cfca.sadk.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>logback</artifactId>
+            <version>${cfca.logback.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>paperless</artifactId>
+            <version>${cfca.paperless.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>SealSADK7</artifactId>
+            <version>${cfca.SealSADK7.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>SealSADK</artifactId>
+            <version>${cfca.SealSADK.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cfca.sadk</groupId>
+            <artifactId>timestampAPI</artifactId>
+            <version>${cfca.timestampAPI.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 253 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/connector/HttpClient.java

@@ -0,0 +1,253 @@
+package me.zhengjie.sign.connector;
+
+import me.zhengjie.sign.constant.Request;
+import me.zhengjie.sign.util.CommonUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.*;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+@Component
+public class HttpClient {
+    @Value("${axq.proxy.port}")
+    private String proxyPort;
+    @Value("${axq.proxy.host}")
+    private String proxyHost;
+    @Value("${axq.proxy.user}")
+    private String authUser;
+    @Value("${axq.proxy.password}")
+    private String authPassword;
+    @Value("${axq.proxy.usable}")
+    private String isProxyUsed;
+
+    public static final String PREFIX = "--", LINEND = "\r\n", DEFAULT_CHARSET = "UTF-8";
+    public static final int DEFAULT_BUFFER_SIZE = 2048, DEFAULT_FILE_BUFFER_SIZE = 10 * 1024, DEFAULT_CONNECT_TIMEOUT = 3000, DEFAULT_READ_TIMEOUT = 15000;
+
+    public static final String DEFAULT_SSL_PROTOCOL = "TLSv1.2", DEFAULT_HTTP_USER_AGENT = "client", DEFAULT_HTTP_CONNECTION = "close",
+            DEFAULT_HTTP_CONTENT_TYPE = "text/plain", DEFAULT_HTTP_ACCEPT = "text/plain";
+
+    public static final String DEFAULT_KEY_ALGORITHM = KeyManagerFactory.getDefaultAlgorithm(), DEFAULT_KEY_STORE_TYPE = KeyStore.getDefaultType(),
+            DEFAULT_TRUST_ALGORITHM = TrustManagerFactory.getDefaultAlgorithm(), DEFAULT_TRUST_STORE_TYPE = KeyStore.getDefaultType();
+
+    private static HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
+        @Override
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    };
+
+    public Config config = new Config();
+    public SSLConfig sslConfig = new SSLConfig();
+    public HttpConfig httpConfig = new HttpConfig();
+
+    private SSLSocketFactory sslSocketFactory;
+
+    public void initSSL(String keyStorePath, char[] keyStorePassword, String trustStorePath, char[] trustStorePassword)
+            throws GeneralSecurityException, IOException {
+        KeyManagerFactory keyManagerFactory = null;
+        KeyStore keyStore = null;
+        if (CommonUtil.isEmpty(sslConfig.keyProvider)) {
+            keyManagerFactory = KeyManagerFactory.getInstance(sslConfig.keyAlgorithm);
+            if (CommonUtil.isNotEmpty(sslConfig.keyStoreType)) {
+                keyStore = KeyStore.getInstance(sslConfig.keyStoreType);
+            }
+        } else {
+            keyManagerFactory = KeyManagerFactory.getInstance(sslConfig.keyAlgorithm, sslConfig.keyProvider);
+            if (CommonUtil.isNotEmpty(sslConfig.keyStoreType)) {
+                keyStore = KeyStore.getInstance(sslConfig.keyStoreType, sslConfig.keyProvider);
+            }
+        }
+        if (CommonUtil.isEmpty(keyStorePath)) {
+            keyManagerFactory.init(keyStore, keyStorePassword);
+        } else {
+            try (FileInputStream fileInputStream = new FileInputStream(keyStorePath)) {
+                keyStore.load(fileInputStream, keyStorePassword);
+                keyManagerFactory.init(keyStore, keyStorePassword);
+            }
+        }
+
+        TrustManagerFactory trustManagerFactory = null;
+        KeyStore trustStore = null;
+        if (CommonUtil.isEmpty(sslConfig.trustProvider)) {
+            trustManagerFactory = TrustManagerFactory.getInstance(sslConfig.trustAlgorithm);
+            if (CommonUtil.isNotEmpty(sslConfig.trustStoreType)) {
+                trustStore = KeyStore.getInstance(sslConfig.trustStoreType);
+            }
+        } else {
+            trustManagerFactory = TrustManagerFactory.getInstance(sslConfig.trustAlgorithm, sslConfig.trustProvider);
+            if (CommonUtil.isNotEmpty(sslConfig.trustStoreType)) {
+                trustStore = KeyStore.getInstance(sslConfig.trustStoreType, sslConfig.trustProvider);
+            }
+        }
+        if (CommonUtil.isEmpty(trustStorePath)) {
+            trustManagerFactory.init(trustStore);
+        } else {
+            try (FileInputStream fileInputStream = new FileInputStream(trustStorePath)) {
+                trustStore.load(fileInputStream, trustStorePassword);
+                trustManagerFactory.init(trustStore);
+            }
+        }
+
+        SSLContext sslContext = CommonUtil.isEmpty(sslConfig.sslProvider) ? SSLContext.getInstance(sslConfig.sslProtocol)
+                : SSLContext.getInstance(sslConfig.sslProtocol, sslConfig.sslProvider);
+        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
+        sslSocketFactory = sslContext.getSocketFactory();
+    }
+
+    public HttpURLConnection connect(String url, String method) throws IOException {
+        System.out.println("url:" + url);
+        HttpURLConnection connection = null;
+        if(Request.PROXY_IN_USED.equals(isProxyUsed)){
+            Authenticator.setDefault(new MyAuthenticator(authUser,authPassword));
+            SocketAddress sa = new InetSocketAddress(proxyHost,Integer.parseInt(proxyPort));
+            Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
+            connection = (HttpURLConnection) new URL(url).openConnection(proxy);
+        }else{
+            connection = (HttpURLConnection) new URL(url).openConnection();
+        }
+        if (sslSocketFactory != null) {
+            HttpsURLConnection httpsConn = (HttpsURLConnection) connection;
+            httpsConn.setSSLSocketFactory(sslSocketFactory);
+            if (sslConfig.ignoreHostname) {
+                httpsConn.setHostnameVerifier(ignoreHostnameVerifier);
+            }
+        }
+        connection.setConnectTimeout(config.connectTimeout);
+        connection.setReadTimeout(config.readTimeout);
+        connection.setDoInput(true);
+        connection.setDoOutput(true);
+        connection.setUseCaches(false);
+        connection.setRequestMethod(method);
+        connection.setRequestProperty("User-Agent", httpConfig.userAgent);
+        connection.setRequestProperty("Connection", httpConfig.connection);
+        connection.setRequestProperty("Content-Type", httpConfig.contentType + ";charset=" + config.charset);
+        connection.setRequestProperty("Accept", httpConfig.accept);
+        connection.setRequestProperty("Accept-Charset", config.charset);
+        return connection;
+    }
+
+    public int send(HttpURLConnection connection, byte[] requestData) throws IOException {
+        if (requestData != null) {
+            connection.setFixedLengthStreamingMode(requestData.length);
+            connection.connect();
+            OutputStream outputStream = connection.getOutputStream();
+            outputStream.write(requestData);
+            outputStream.flush();
+        } else {
+            connection.connect();
+        }
+        return connection.getResponseCode();
+    }
+
+    public int sendFile(HttpURLConnection connection, Map<String, String> paramMap, InputStream is, String fileName, String contentType) throws IOException {
+        if (CommonUtil.isNotEmpty(paramMap)) {
+            String BOUNDARY = java.util.UUID.randomUUID().toString();
+            connection.setRequestProperty("Connection", DEFAULT_HTTP_CONNECTION);
+            connection.setRequestProperty("Charsert", DEFAULT_CHARSET);
+            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
+
+            DataOutputStream os = new DataOutputStream(connection.getOutputStream());
+            for (Entry<String, String> entry : paramMap.entrySet()) {
+                addTextBody(entry.getKey(), entry.getValue(), BOUNDARY, os);
+            }
+
+            if (is != null) {
+                addBinaryBody(Request.CONTRACT_FILE, fileName, contentType, BOUNDARY, is, os);
+            }
+
+            byte[] end_data = CommonUtil.getBytes(PREFIX + BOUNDARY + PREFIX + LINEND);
+            os.write(end_data);
+            os.flush();
+        } else {
+            connection.connect();
+        }
+        return connection.getResponseCode();
+    }
+
+    private void addTextBody(String name, String text, String BOUNDARY, DataOutputStream os) throws IOException {
+        StringBuilder sb = new StringBuilder(PREFIX).append(BOUNDARY).append(LINEND);
+        sb.append("Content-Disposition: form-data; name=\"").append(name).append("\"").append(LINEND);
+        sb.append(LINEND).append(text).append(LINEND);
+        os.write(CommonUtil.getBytes(sb.toString()));
+    }
+
+    private void addBinaryBody(String name, String fileName, String contentType, String BOUNDARY, InputStream is, DataOutputStream os) throws IOException {
+        StringBuilder sb = new StringBuilder(PREFIX).append(BOUNDARY).append(LINEND);
+        sb.append("Content-Disposition: form-data; name=\"").append(name).append("\"; filename=\"").append(fileName).append("\"").append(LINEND);
+        sb.append("Content-Type: ").append(contentType).append(LINEND).append(LINEND);
+        os.write(CommonUtil.getBytes(sb.toString()));
+
+        byte[] buffer = new byte[DEFAULT_FILE_BUFFER_SIZE];
+        int read = -1;
+        while ((read = is.read(buffer)) != -1) {
+            os.write(buffer, 0, read);
+        }
+        os.write(CommonUtil.getBytes(LINEND));
+    }
+
+    public byte[] receive(HttpURLConnection connection) throws IOException {
+        InputStream inputStream = connection.getErrorStream();
+        if (inputStream == null) {
+            inputStream = connection.getInputStream();
+        }
+        ByteArrayOutputStream os = new ByteArrayOutputStream(config.bufferSize);
+        byte[] buffer = new byte[config.bufferSize];
+        int read = -1, length = 0;
+        while ((read = inputStream.read(buffer)) != -1) {
+            os.write(buffer, 0, read);
+            length += read;
+        }
+        System.out.println("length:" + length);
+        return os.toByteArray();
+    }
+
+    public void disconnect(HttpURLConnection connection) {
+        Optional.ofNullable(connection).ifPresent(HttpURLConnection::disconnect);
+    }
+
+    public static class Config {
+        public String charset = DEFAULT_CHARSET;
+        public int bufferSize = DEFAULT_BUFFER_SIZE;
+        public int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
+        public int readTimeout = DEFAULT_READ_TIMEOUT;
+    }
+
+    public static class SSLConfig {
+        public String sslProvider = null;
+        public String sslProtocol = DEFAULT_SSL_PROTOCOL;
+        public String keyProvider = null;
+        public String keyAlgorithm = DEFAULT_KEY_ALGORITHM;
+        public String keyStoreType = DEFAULT_KEY_STORE_TYPE;
+        public String trustProvider = null;
+        public String trustAlgorithm = DEFAULT_TRUST_ALGORITHM;
+        public String trustStoreType = DEFAULT_TRUST_STORE_TYPE;
+        public boolean ignoreHostname = true;
+    }
+
+    public static class HttpConfig {
+        public String userAgent = DEFAULT_HTTP_USER_AGENT;
+        public String connection = DEFAULT_HTTP_CONNECTION;
+        public String contentType = DEFAULT_HTTP_CONTENT_TYPE;
+        public String accept = DEFAULT_HTTP_ACCEPT;
+    }
+
+    private static class MyAuthenticator extends Authenticator {
+        private String user = "";
+        private String password = "";
+        public MyAuthenticator(String user, String password) {
+            this.user = user;
+            this.password = password;
+        }
+        protected PasswordAuthentication getPasswordAuthentication() {
+            return new PasswordAuthentication(user, password.toCharArray());
+        }
+    }
+}

+ 199 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/connector/HttpConnector.java

@@ -0,0 +1,199 @@
+package me.zhengjie.sign.connector;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import me.zhengjie.sign.constant.MIMEType;
+import me.zhengjie.sign.constant.Request;
+import me.zhengjie.sign.constant.SystemConst;
+import me.zhengjie.sign.util.CommonUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+@Component
+@Getter
+@RequiredArgsConstructor
+public class HttpConnector {
+    private final HttpClient httpClient;
+    @Value("${axq.connect.connectTimeout}")
+    private int connectTimeout;
+    @Value("${axq.connect.readTimeout}")
+    private int readTimeout;
+    @Value("${axq.connect.isSSL}")
+    private boolean isSSL;
+    @Value("${axq.request.jksPath}")
+    private String jksPath;
+    @Value("${axq.request.jksPWD}")
+    private String keyStorePassword;
+    @Value("${axq.request.jksPWD}")
+    private String trustStorePassword;
+    @Value("${axq.request.cfcaURL}")
+    private String url;
+    @Value("${axq.request.channel}")
+    private String channel;
+    @Value("${axq.connect.alias}")
+    private String alias;
+    @Value("${axq.request.platID}")
+    private String platID;
+    private String keyStorePath;
+    private String trustStorePath;
+
+    public void init() {
+        String path = HttpConnector.class.getClassLoader().getResource("").getPath() + jksPath;
+        keyStorePath = path;
+        trustStorePath = path;
+        httpClient.config.connectTimeout = connectTimeout;
+        httpClient.config.readTimeout = readTimeout;
+        httpClient.httpConfig.userAgent = "TrustSign FEP";
+        httpClient.httpConfig.contentType = MIMEType.FORM;
+        httpClient.httpConfig.accept = MIMEType.JSON;
+        try {
+            if (isSSL) {
+                httpClient.initSSL(keyStorePath, keyStorePassword.toCharArray(), trustStorePath, trustStorePassword.toCharArray());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (!url.endsWith("/")) {
+            url += "/";
+        }
+    }
+
+    public String post(String uri, String data, String signature) {
+        return deal(uri, "POST", prepare(data, signature, null));
+    }
+
+    public String post(String uri, String data, String signature, Map<String, String> map) {
+        return deal(uri, "POST", prepare(data, signature, map));
+    }
+
+    public String post(String uri, String data, String signature, File file) {
+        return dealFile(uri, "POST", data, file, signature);
+    }
+
+    public String post(String uri, String data, String signature, InputStream file, String fileName) {
+        return dealFile(uri, "POST", data, file, fileName, signature);
+    }
+
+    public byte[] getFile(String uri) {
+        HttpURLConnection connection = null;
+        try {
+            connection = httpClient.connect(url + uri, "GET");
+
+            int responseCode = httpClient.send(connection, null);
+            System.out.println("responseCode:" + responseCode);
+            if (responseCode != 200) {
+                System.out.println(CommonUtil.getString(httpClient.receive(connection)));
+                return null;
+            }
+            return httpClient.receive(connection);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        } finally {
+            httpClient.disconnect(connection);
+        }
+    }
+
+    private String prepare(String data, String signature, Map<String, String> map) {
+        try {
+            StringBuilder request = new StringBuilder();
+            request.append(Request.CHANNEL).append("=").append(URLEncoder.encode(channel, SystemConst.DEFAULT_CHARSET));
+            if (CommonUtil.isNotEmpty(data)) {
+                request.append("&").append(Request.DATA).append("=").append(URLEncoder.encode(data, SystemConst.DEFAULT_CHARSET));
+            }
+            if (CommonUtil.isNotEmpty(signature)) {
+                request.append("&").append(Request.SIGNATURE).append("=").append(URLEncoder.encode(signature, SystemConst.DEFAULT_CHARSET));
+            }
+            // 如果要返回英文错误信息需要加上这个参数
+            // request.append("&").append(Request.LOCALE).append("=").append(URLEncoder.encode(Locale.US.toString(), SystemConst.DEFAULT_CHARSET));
+            if (CommonUtil.isNotEmpty(map)) {
+                for (Entry<String, String> pair : map.entrySet()) {
+                    request.append("&").append(pair.getKey()).append("=")
+                            .append(pair.getValue() == null ? "" : URLEncoder.encode(pair.getValue(), SystemConst.DEFAULT_CHARSET));
+                }
+            }
+            return request.toString();
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    private String deal(String uri, String method, String request) {
+        HttpURLConnection connection = null;
+        try {
+            connection = httpClient.connect(url + uri, method);
+            int responseCode = httpClient.send(connection, request == null ? null : CommonUtil.getBytes(request));
+            System.out.println("responseCode:" + responseCode);
+            return CommonUtil.getString(httpClient.receive(connection));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return e.getMessage();
+        } finally {
+            httpClient.disconnect(connection);
+        }
+    }
+
+    private String dealFile(String uri, String method, String request, File file, String signature) {
+        HttpURLConnection connection = null;
+        try (FileInputStream is = new FileInputStream(file)) {
+            connection = httpClient.connect(url + uri, method);
+            Map<String, String> paramMap = new HashMap<>(4);
+            paramMap.put(Request.DATA, request);
+            paramMap.put(Request.SIGNATURE, signature);
+            int responseCode = httpClient.sendFile(connection, paramMap, is, file.getName(), MIMEType.PDF);
+            System.out.println("responseCode:" + responseCode);
+            return CommonUtil.getString(httpClient.receive(connection));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return e.getMessage();
+        } finally {
+            httpClient.disconnect(connection);
+        }
+    }
+
+    /**
+     * 处理文件流
+     *
+     * @param uri
+     * @param method
+     * @param request
+     * @param fileName
+     * @param signature
+     * @return
+     */
+    private String dealFile(String uri, String method, String request, InputStream is, String fileName, String signature) {
+        HttpURLConnection connection = null;
+        String var8;
+        try {
+            try {
+                connection = this.httpClient.connect(this.url + uri, method);
+                Map<String, String> paramMap = new HashMap<>(4);
+                paramMap.put("data", request);
+                paramMap.put("signature", signature);
+                int responseCode = this.httpClient.sendFile(connection, paramMap, is, fileName, "application/pdf");
+                System.out.println("responseCode:" + responseCode);
+                String var11 = CommonUtil.getString(this.httpClient.receive(connection));
+                return var11;
+            } catch (Throwable var29) {
+                throw var29;
+            } finally {
+                is.close();
+            }
+        } catch (Exception var31) {
+            var8 = var31.getMessage();
+        } finally {
+            httpClient.disconnect(connection);
+        }
+        return var8;
+    }
+}

+ 13 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/constant/MIMEType.java

@@ -0,0 +1,13 @@
+package me.zhengjie.sign.constant;
+
+public class MIMEType {
+    public static final String FORM = "application/x-www-form-urlencoded";
+    public static final String JSON = "application/json";
+    public static final String XML = "application/xml";
+    public static final String PDF = "application/pdf";
+    public static final String HTML = "text/html";
+    public static final String PLAIN = "text/plain";
+    public static final String IMAGE = "image/*";
+    public static final String DOC = "application/msword";
+    public static final String DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+}

+ 9 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/constant/Request.java

@@ -0,0 +1,9 @@
+package me.zhengjie.sign.constant;
+
+public class Request {
+    public static final String CHANNEL = "channel";
+    public static final String DATA = "data";
+    public static final String SIGNATURE = "signature";
+    public static final String CONTRACT_FILE = "contractFile";
+    public static final String PROXY_IN_USED = "1";
+}

+ 5 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/constant/SystemConst.java

@@ -0,0 +1,5 @@
+package me.zhengjie.sign.constant;
+
+public class SystemConst {
+    public static final String DEFAULT_CHARSET = "UTF-8";
+}

+ 38 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/converter/JsonObjectMapper.java

@@ -0,0 +1,38 @@
+package me.zhengjie.sign.converter;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class JsonObjectMapper extends ObjectMapper {
+    private static final long serialVersionUID = 1L;
+
+    public JsonObjectMapper() {
+        this.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+        this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        this.setSerializationInclusion(Include.NON_NULL);
+    }
+
+    @Override
+    public <T> T readValue(String content, Class<T> valueType) {
+        try {
+            return super.readValue(content, valueType);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public String writeValueAsString(Object object) {
+        try {
+            return super.writeValueAsString(object);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 130 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/util/CommonUtil.java

@@ -0,0 +1,130 @@
+package me.zhengjie.sign.util;
+
+import me.zhengjie.sign.constant.SystemConst;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class CommonUtil {
+    private static final String MASK = "[^ -()]";
+    private static final String MASK_CHAR = "*";
+    private static final String LIKE_CHAR = "%";
+
+    public static boolean isEmpty(String str) {
+        return (str == null || str.trim().length() == 0);
+    }
+
+    public static boolean isNotEmpty(String str) {
+        return (str != null && str.trim().length() != 0);
+    }
+
+    public static boolean isEmpty(String[] strs) {
+        return (strs == null || strs.length == 0);
+    }
+
+    public static boolean isNotEmpty(String[] strs) {
+        return (strs != null && strs.length != 0);
+    }
+
+    public static <T> boolean isEmpty(List<T> list) {
+        return (list == null || list.isEmpty());
+    }
+
+    public static <T> boolean isNotEmpty(List<T> list) {
+        return (list != null && !list.isEmpty());
+    }
+
+    public static <K, V> boolean isEmpty(Map<K, V> map) {
+        return (map == null || map.isEmpty());
+    }
+
+    public static <K, V> boolean isNotEmpty(Map<K, V> map) {
+        return (map != null && !map.isEmpty());
+    }
+
+    public static <K, V> List<V> mapToList(Map<K, V> map) {
+        List<V> list = new ArrayList<V>();
+        list.addAll(map.values());
+        return list;
+    }
+
+    public static int booleanToInt(Boolean bool) {
+        return bool == null ? 0 : (bool ? 1 : 0);
+    }
+
+    public static boolean intToBoolean(Integer i) {
+        return i == null ? false : (i != 0 ? true : false);
+    }
+
+    public static Number nvl(Number obj, Number value) {
+        if (obj == null) {
+            return value;
+        } else {
+            return obj;
+        }
+    }
+
+    public static String nvl(String str, String value) {
+        if (isEmpty(str)) {
+            return value;
+        } else {
+            return str;
+        }
+    }
+
+    public static byte[] getBytes(String str) {
+        try {
+            return str.getBytes(SystemConst.DEFAULT_CHARSET);
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    public static String getString(byte[] bytes) {
+        try {
+            return new String(bytes, SystemConst.DEFAULT_CHARSET);
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    public static String toString(String[] strings) {
+        if (strings == null)
+            return "";
+        int iMax = strings.length - 1;
+        if (iMax == -1)
+            return "";
+
+        StringBuilder b = new StringBuilder();
+        for (int i = 0;; i++) {
+            b.append(String.valueOf(strings[i]));
+            if (i == iMax)
+                return b.toString();
+            b.append(";");
+        }
+    }
+
+    public static String mask(String str, int begin, int end) {
+        return str.substring(0, begin) + str.substring(begin, end).replaceAll(MASK, MASK_CHAR) + str.substring(end, str.length());
+    }
+
+    public static String getLikeStr(String str) {
+        return LIKE_CHAR + str + LIKE_CHAR;
+    }
+
+    public static String formatSerialNo(String serialNo) {
+        int length = serialNo.length();
+        if (length >= 30 && length < 32) {
+            char[] temp = new char[32];
+            for (int i = 0; i < 32 - length; i++) {
+                temp[i] = '0';
+            }
+            serialNo.getChars(0, length, temp, 32 - length);
+            return new String(temp);
+        } else {
+            return serialNo;
+        }
+    }
+}

+ 97 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/util/PdfUtil.java

@@ -0,0 +1,97 @@
+package me.zhengjie.sign.util;
+
+import cfca.sadk.algorithm.common.PKIException;
+import cfca.sadk.com.itextpdf.kernel.color.Color;
+import cfca.sadk.lib.crypto.JCrypto;
+import cfca.sadk.lib.crypto.Session;
+import cfca.sadk.seal.base.bean.appearance.AbstractAppearance.GSBlendMode;
+import cfca.sadk.seal.base.bean.appearance.BlankAppearance;
+import cfca.sadk.seal.base.bean.appearance.GraphicAppearance;
+import cfca.sadk.seal.base.bean.sign.SealResultInfo;
+import cfca.sadk.seal.base.bean.sign.SignInfoConfig;
+import cfca.sadk.seal.base.bean.sign.SignInfoConfig.SignatureVersion;
+import cfca.sadk.seal.base.exception.SealException;
+import cfca.sadk.seal.base.external.AbstractExternalP7Signer;
+import cfca.sadk.seal.base.util.AsynCFCASigner;
+import cfca.sadk.seal.util.AsyncSignatureUtil;
+import cfca.sadk.system.Mechanisms;
+import cfca.sadk.x509.certificate.X509Cert;
+
+import java.text.ParseException;
+
+public class PdfUtil {
+    private static final String REASON = "电子签名";
+    private static final String LOCATION = "北京";
+    private static final float TRANSPARENCY = 0.8f;
+
+    private static Session session = null;
+    static {
+        try {
+            String deviceName = JCrypto.JSOFT_LIB;
+            JCrypto.getInstance().initialize(deviceName, null);
+            session = JCrypto.getInstance().openSession(deviceName);
+
+            // FontUtil.getInstance("./ttf/simsun_new.ttf");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static byte[] combineExternalSignature(byte[] pdfBytes, byte[] signedBytes, X509Cert x509Cert, String signLocationField) throws Exception {
+        try {
+            AbstractExternalP7Signer asynCFCASigner;
+            if (x509Cert.isSM2Cert()) {
+                asynCFCASigner = new AsynCFCASigner(signedBytes, Mechanisms.M_SM3_SM2);
+            } else {
+                asynCFCASigner = new AsynCFCASigner(signedBytes, Mechanisms.M_SHA256_RSA);
+            }
+
+            GraphicAppearance appearance = new GraphicAppearance();
+            appearance.setSignFieldName(signLocationField);
+            SealResultInfo result = AsyncSignatureUtil.combineExternalP7Signature(pdfBytes, appearance, asynCFCASigner);
+            return result.getSignedPDFData();
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    public static boolean isPdf(byte[] pdfBytes) {
+        if (pdfBytes.length > 5 && pdfBytes[0] == 0x25 && pdfBytes[1] == 0x50 && pdfBytes[2] == 0x44 && pdfBytes[3] == 0x46 && pdfBytes[4] == 0x2D) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private static BlankAppearance getBlankAppearance(byte[] imageBytes, String signText, Color color, String signLocationField)
+            throws ParseException, SealException {
+        BlankAppearance appearance = new BlankAppearance();
+        appearance.setReason(REASON);
+        appearance.setLocation(LOCATION);
+        if (null != imageBytes) {
+            appearance.setStamperSr(imageBytes);
+            appearance.setGSBlendMode(GSBlendMode.MULTIPLY);
+        } else {
+            appearance.setSignText(signText);
+            appearance.setFontColor(color);
+            appearance.setBold(false);
+        }
+        appearance.setSignFieldName(signLocationField);
+        appearance.setTransparency(TRANSPARENCY);
+        return appearance;
+    }
+
+    private static SignInfoConfig getSignInfoConfigAsyn(X509Cert x509Cert) throws PKIException, SealException {
+        SignInfoConfig signInfoConfig = new SignInfoConfig();
+        signInfoConfig.setSession(session);
+        signInfoConfig.setChain(new X509Cert[] { x509Cert });
+        if (x509Cert.isSM2Cert()) {
+            signInfoConfig.setSignAlg(Mechanisms.M_SM3_SM2);
+            signInfoConfig.setSignatureVersion(SignatureVersion.VERSION_0);
+        } else {
+            signInfoConfig.setSignAlg(Mechanisms.M_SHA256_RSA);
+        }
+        signInfoConfig.setAsyn(true);
+        return signInfoConfig;
+    }
+}

+ 161 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/util/SecurityUtil.java

@@ -0,0 +1,161 @@
+package me.zhengjie.sign.util;
+
+import cfca.sadk.algorithm.common.Mechanism;
+import cfca.sadk.algorithm.common.PKIException;
+import cfca.sadk.lib.crypto.JCrypto;
+import cfca.sadk.lib.crypto.Session;
+import cfca.sadk.util.*;
+import cfca.sadk.x509.certificate.X509Cert;
+import me.zhengjie.sign.constant.SystemConst;
+
+import java.security.PrivateKey;
+
+public class SecurityUtil {
+    private static Session session = null;
+
+    static {
+        String deviceName = JCrypto.JSOFT_LIB;
+        try {
+            JCrypto.getInstance().initialize(deviceName, null);
+            session = JCrypto.getInstance().openSession(deviceName);
+        } catch (PKIException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static String getSignCert(String pfxPath, String pfxPWD) throws PKIException {
+        try {
+            X509Cert x509Cert = CertUtil.getCertFromPFX(pfxPath, pfxPWD);
+
+            return Base64.toBase64String(x509Cert.getEncoded());
+        } catch (Exception e) {
+            throw new PKIException("get signature cert fail", e);
+        }
+    }
+
+    public static String getSM2SignCert(String sm2Path) throws PKIException {
+        try {
+            X509Cert x509Cert = CertUtil.getCertFromSM2(sm2Path);
+
+            return Base64.toBase64String(x509Cert.getEncoded());
+        } catch (Exception e) {
+            throw new PKIException("get signature cert fail", e);
+        }
+    }
+
+    public static String p1SignMessage(String pfxPath, String pfxPWD, byte[] sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromPFX(pfxPath, pfxPWD);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p1SignMessage(Mechanism.SHA256_RSA, sourceData, privateKey, session);
+            return new String(signatureByte, SystemConst.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            throw new PKIException("P1 signature message fail", e);
+        }
+    }
+
+    public static String p1SM2SignMessage(String sm2Path, String pfxPWD, byte[] sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromSM2(sm2Path, pfxPWD);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p1SignMessage(Mechanism.SM3_SM2, sourceData, privateKey, session);
+            return new String(signatureByte, SystemConst.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            throw new PKIException("P1 signature message fail", e);
+        }
+    }
+
+    public static String p7SignByHash(String pfxPath, String pfxPWD, byte[] sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromPFX(pfxPath, pfxPWD);
+            X509Cert x509Cert = CertUtil.getCertFromPFX(pfxPath, pfxPWD);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p7SignByHash(Mechanism.SHA256_RSA, sourceData, privateKey, x509Cert, session);
+            return new String(signatureByte, SystemConst.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            throw new PKIException("P7 hash signature fail", e);
+        }
+    }
+
+    public static String p7SM2SignByHash(String sm2Path, String pfxPWD, byte[] sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromSM2(sm2Path, pfxPWD);
+            X509Cert x509Cert = CertUtil.getCertFromSM2(sm2Path);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p7SignByHash(Mechanism.SM3_SM2, sourceData, privateKey, x509Cert, session);
+            return new String(signatureByte, SystemConst.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            throw new PKIException("SM2 P7 hash signature fail", e);
+        }
+    }
+
+    public static String p7SignMessageDetach(String pfxPath, String pfxPWD, byte[] sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromPFX(pfxPath, pfxPWD);
+            X509Cert signCert = CertUtil.getCertFromPFX(pfxPath, pfxPWD);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p7SignMessageDetach(Mechanism.SHA256_RSA, sourceData, privateKey, signCert, session);
+            return new String(signatureByte);
+        } catch (Exception e) {
+            throw new PKIException("P7 detach signature fail", e);
+        }
+    }
+
+    public static String p7SignMessageDetach(String jksPath, String jksPWD, String alias, String sourceData) throws PKIException {
+        try {
+            PrivateKey privateKey = KeyUtil.getPrivateKeyFromJKS(jksPath, jksPWD, alias);
+            X509Cert signCert = CertUtil.getCertFromJKS(jksPath, jksPWD, alias);
+
+            Signature signature = new Signature();
+            byte[] signatureByte = signature.p7SignMessageDetach(Mechanism.SHA256_RSA, CommonUtil.getBytes(sourceData), privateKey, signCert, session);
+            return new String(signatureByte);
+        } catch (Exception e) {
+            throw new PKIException("P7 detach signature fail", e);
+        }
+    }
+
+    public static Signature verifyP7Detach(byte[] original, byte[] signature) throws PKIException {
+        Signature sign = new Signature();
+        if (!sign.p7VerifyMessageDetach(original, signature, session)) {
+            throw new PKIException("verify P7 detach signature fail");
+        }
+        return sign;
+    }
+
+    public static Signature verifyP7ByHash(byte[] original, byte[] signature) throws PKIException {
+        Signature sign = new Signature();
+        if (!sign.p7VerifyByHash(original, signature, session)) {
+            throw new PKIException("verify P7 signature by hash fail");
+        }
+        return sign;
+    }
+
+    public static Signature verifyP7Detach(String original, String signature) throws PKIException {
+        return verifyP7Detach(CommonUtil.getBytes(original), CommonUtil.getBytes(signature));
+    }
+
+    public static X509Cert getX509CertFromSignature(String signature) throws PKIException {
+        return new Signature().getSignerX509CertFromP7SignData(CommonUtil.getBytes(signature));
+    }
+
+    public static String encryptBySM4(String plaintext, String password) throws PKIException {
+        return CommonUtil.getString(EncryptUtil.encryptMessageBySM4(CommonUtil.getBytes(plaintext), password));
+    }
+
+    public static String decryptBySM4(String ciphertext, String password) throws PKIException {
+        return CommonUtil.getString(EncryptUtil.decryptMessageBySM4(CommonUtil.getBytes(ciphertext), password));
+    }
+
+    public static P10Request getP10Request() {
+        return new P10Request(session);
+    }
+
+    public static String getP10(P10Request p10Request, int length) throws PKIException {
+        return CommonUtil.getString(p10Request.generatePKCS10Request(new Mechanism(Mechanism.SHA1_RSA), length, session));
+    }
+}

+ 38 - 0
eladmin-sign/src/main/java/me/zhengjie/sign/util/TimeUtil.java

@@ -0,0 +1,38 @@
+package me.zhengjie.sign.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+public class TimeUtil {
+    public static final String FORMAT_14 = "yyyyMMddHHmmss";
+    public static final String FORMAT_14_TEXT = "yyyy-MM-dd HH:mm:ss";
+    public static final String FORMAT_8 = "yyyyMMdd";
+    public static final String FORMAT_8_TEXT = "yyyy-MM-dd";
+    public static final String FORMAT_6 = "HHmmss";
+    public static final String FORMAT_6_TEXT = "HH:mm:ss";
+
+    public static String getTimeInFormat(Date date, String format) {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static Date getDateInFormat(String time, String format) throws ParseException {
+        return new SimpleDateFormat(format).parse(time);
+    }
+
+    public static String getCurrentTime(String format) {
+        return getTimeInFormat(new Date(), format);
+    }
+
+    public static Date getOffsetDate(Date date, int field, int amount) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(field, amount);
+        return calendar.getTime();
+    }
+
+    public static String getChangedFormat(String time, String fromFormat, String toFormat) throws ParseException {
+        return new SimpleDateFormat(toFormat).format(new SimpleDateFormat(fromFormat).parse(time));
+    }
+}