feat(nifi): 添加招商银行CBS接口调用功能
- 新增 hzya-nifi-Zsyh-cbs-nar 和 hzya-nifi-Zsyh-cbs-processors 模块 - 实现了与招商银行CBS系统交互的常量类、工具类和处理器 - 添加了SM2加密解密功能 - 集成了Bouncy Castle加密库 -编写了单元测试用例
This commit is contained in:
parent
0e2554bf2e
commit
3699d0b6e5
|
@ -0,0 +1,34 @@
|
||||||
|
<?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>nifi-hzyadev-bundle</artifactId>
|
||||||
|
<groupId>com.hzya</groupId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>hzya-nifi-Zsyh-cbs-nar</artifactId>
|
||||||
|
|
||||||
|
<packaging>nar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hzya</groupId>
|
||||||
|
<artifactId>hzya-nifi-Zjnx-czb-processors</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.nifi</groupId>
|
||||||
|
<artifactId>nifi-standard-services-api-nar</artifactId>
|
||||||
|
<version>${nifi-revision}</version>
|
||||||
|
<type>nar</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?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>nifi-hzyadev-bundle</artifactId>
|
||||||
|
<groupId>com.hzya</groupId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>hzya-nifi-Zsyh-cbs-processors</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.nifi</groupId>
|
||||||
|
<artifactId>nifi-api</artifactId>
|
||||||
|
<version>${nifi-revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.nifi</groupId>
|
||||||
|
<artifactId>nifi-dbcp-service-api</artifactId>
|
||||||
|
<version>${nifi-revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.nifi</groupId>
|
||||||
|
<artifactId>nifi-processor-utils</artifactId>
|
||||||
|
<version>1.15.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.nifi</groupId>
|
||||||
|
<artifactId>nifi-mock</artifactId>
|
||||||
|
<version>${nifi-revision}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>mockwebserver</artifactId>
|
||||||
|
<version>4.9.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.11.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk18on</artifactId>
|
||||||
|
<version>1.78.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.projectlombok</groupId>-->
|
||||||
|
<!-- <artifactId>lombok</artifactId>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.7.36</version>
|
||||||
|
<!-- <scope>provided</scope>-->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.slf4j</groupId>-->
|
||||||
|
<!-- <artifactId>slf4j-api</artifactId>-->
|
||||||
|
<!-- <version>1.7.36</version> </dependency>-->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>1.7.36</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.hzya.frame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:liuyang
|
||||||
|
* @Package:com.hzya.frame
|
||||||
|
* @Project:nifi-hzyadev-bundle
|
||||||
|
* @name:ZsyhCbs
|
||||||
|
* @Date:2025/9/9 14:14
|
||||||
|
* @Filename:ZsyhCbs
|
||||||
|
*/
|
||||||
|
public class ZsyhCbs {
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.hzya.frame.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: KeXue
|
||||||
|
* @time: 2022/8/25
|
||||||
|
* @description: 常量类
|
||||||
|
*/
|
||||||
|
public interface Constants {
|
||||||
|
|
||||||
|
String TARGET_CONTENT_TYPE = "application/json";
|
||||||
|
|
||||||
|
String SIGN_HEADER_NAME = "X-MBCLOUD-API-SIGN";
|
||||||
|
|
||||||
|
String TIMESTAMP_HEADER = "X-MBCLOUD-TIMESTAMP";
|
||||||
|
|
||||||
|
String ENCRYPTION_ENABLED_HEADER_NAME = "X-MBCLOUD-ENCRYPTION-ENABLED";
|
||||||
|
|
||||||
|
String X_MBCLOUD_COMPRESS = "X-Mbcloud-Compress";
|
||||||
|
|
||||||
|
String AUTHORIZATION = "Authorization";
|
||||||
|
|
||||||
|
String BEARER = "Bearer ";
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package com.hzya.frame.util;
|
||||||
|
|
||||||
|
//import com.cmbyc.security.util.SM2Util;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.HttpMessage;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ByteArrayEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.protocol.HTTP;
|
||||||
|
//import org.slf4j.LoggerFactory;
|
||||||
|
//import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: KeXue
|
||||||
|
* @time: 2022/8/25
|
||||||
|
* @description: SM2请求加解密实例
|
||||||
|
*/
|
||||||
|
public class SM2Example {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 财资管理云公钥(平台公钥)
|
||||||
|
*/
|
||||||
|
static final String bodyEncryptionKey = "04D0A5CDD879058F1D4DEFFFCE7F902402026B1C39F03FF426E6C0D43F0EBA5F8617D5ABC7501EA5E53038D93CD33036CEFF2F5A64D226144AB3D6D73CE901C3B8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业私钥(加密)
|
||||||
|
*/
|
||||||
|
static final String signEncryptionPrivateKey = "D735102B815123AFB3B0779928FA8264B050BEB43071DEBD88BB115B28E4661C";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业私钥(解密)
|
||||||
|
*/
|
||||||
|
static final String bodyDecryptionKey = "D735102B815123AFB3B0779928FA8264B050BEB43071DEBD88BB115B28E4661C";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据appid和appsecert获取的token
|
||||||
|
*/
|
||||||
|
static final String token = "3152124a-2705-4cc0-b451-117047ef4d8d";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口路径
|
||||||
|
*/
|
||||||
|
// static final String TARGET_URL = "http://cbs8-gateway-openapi-dev.paas.cmbchina.cn/openapi/account/accounts-current-balance/erp/query";
|
||||||
|
static final String TARGET_URL = "https://cbs8-openapi-reprd.csuat.cmburl.cn/openapi/draft2/openapi/v2/trsinfo/query-trs-info-page";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求体数据
|
||||||
|
*/
|
||||||
|
// static final String requestData = "\n" + "{\"accountNo\":\"\"}";
|
||||||
|
static final String requestData = "{\n" +
|
||||||
|
"\t\"applyDateStart\":\"2025-08-01\",\n" +
|
||||||
|
"\t\"applyDateEnd\":\"2025-08-31\",\n" +
|
||||||
|
"\t\"initAccountList\":\"591915131310106\"\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// private static final Logger log = LoggerFactory.getLogger(SM2Example.class);
|
||||||
|
|
||||||
|
// public static void main(String[] args) throws Exception {
|
||||||
|
// CloseableHttpClient client = HttpClients.custom()
|
||||||
|
// // 禁止HttpClient自动解压缩
|
||||||
|
// .disableContentCompression().build();
|
||||||
|
//
|
||||||
|
// HttpPost httpPost = setupRequest();
|
||||||
|
// try (CloseableHttpResponse response = client.execute(httpPost)) {
|
||||||
|
// byte[] finalResponseData = handleResponse(response);
|
||||||
|
//// log.info("\n返回结果:{}", new String(finalResponseData));
|
||||||
|
// } catch (IOException ignored) {
|
||||||
|
// throw new IOException("网络连接失败或超时!");
|
||||||
|
// } finally {
|
||||||
|
// client.close();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成请求报文
|
||||||
|
*/
|
||||||
|
public static HttpPost setupRequest() {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// 请求数据拼接: 报文体+时间戳
|
||||||
|
byte[] requestDataBytes = requestData.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] timestampBytes = ("×tamp=" + timestamp).getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] newBytes = new byte[requestDataBytes.length + timestampBytes.length];
|
||||||
|
System.arraycopy(requestDataBytes, 0, newBytes, 0, requestDataBytes.length);
|
||||||
|
System.arraycopy(timestampBytes, 0, newBytes, requestDataBytes.length, timestampBytes.length);
|
||||||
|
|
||||||
|
// 生成签名
|
||||||
|
byte[] signature = SM2Util.sign(signEncryptionPrivateKey, newBytes);
|
||||||
|
String sign = Base64.encodeBase64String(SM2Util.encodeDERSignature(signature));
|
||||||
|
// log.info("签名:{}", sign);
|
||||||
|
|
||||||
|
// 设置请求URL
|
||||||
|
HttpPost httpPost = new HttpPost(TARGET_URL);
|
||||||
|
// 请求头设置签名
|
||||||
|
httpPost.setHeader(Constants.SIGN_HEADER_NAME, sign);
|
||||||
|
// 请求头设置时间戳
|
||||||
|
httpPost.setHeader(Constants.TIMESTAMP_HEADER, Long.toString(timestamp));
|
||||||
|
// 请求头设置请求参数格式,请根据实际情况改写
|
||||||
|
httpPost.setHeader(HTTP.CONTENT_TYPE, Constants.TARGET_CONTENT_TYPE);
|
||||||
|
// 请求头设置TOKEN
|
||||||
|
httpPost.setHeader(Constants.AUTHORIZATION, Constants.BEARER + token);
|
||||||
|
|
||||||
|
// 报文体加密
|
||||||
|
byte[] encryptedData = SM2Util.encrypt(bodyEncryptionKey, requestDataBytes);
|
||||||
|
// 设置请求体
|
||||||
|
httpPost.setEntity(new ByteArrayEntity(encryptedData));
|
||||||
|
|
||||||
|
return httpPost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理响应报文
|
||||||
|
*/
|
||||||
|
public static byte[] handleResponse(HttpResponse response) throws Exception {
|
||||||
|
InputStream content = response.getEntity().getContent();
|
||||||
|
byte[] responseData = IOUtils.toByteArray(content);
|
||||||
|
|
||||||
|
if (responseData == null || responseData.length == 0) {
|
||||||
|
return responseData == null ? new byte[0] : responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤1 原始响应报文解密 如果服务网关获取加解密密钥失败,则无法解密请求报文,且无法加密响应报文。 这时候,网关会直接返回错误信息,响应报文是未加密状态。
|
||||||
|
Boolean encryptionEnable = getHeader(response, Constants.ENCRYPTION_ENABLED_HEADER_NAME);
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(encryptionEnable)) {
|
||||||
|
responseData = SM2Util.decrypt(bodyDecryptionKey, responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean xMbcloudCompress = getHeader(response, Constants.X_MBCLOUD_COMPRESS);
|
||||||
|
if (Boolean.TRUE.equals(xMbcloudCompress)) {
|
||||||
|
responseData = decompress(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseData;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Boolean getHeader(HttpMessage message, String name) {
|
||||||
|
Header header = message.getFirstHeader(name);
|
||||||
|
return header != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] decompress(byte[] data) throws IOException {
|
||||||
|
ByteArrayInputStream input = new ByteArrayInputStream(data);
|
||||||
|
GZIPInputStream gzipInput = new GZIPInputStream(input);
|
||||||
|
return IOUtils.toByteArray(gzipInput);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
package com.hzya.frame.util;
|
||||||
|
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.*;
|
||||||
|
import org.bouncycastle.crypto.engines.SM2Engine;
|
||||||
|
import org.bouncycastle.crypto.params.*;
|
||||||
|
import org.bouncycastle.crypto.signers.SM2Signer;
|
||||||
|
//import org.bouncycastle.jce.ECNamedCurveTable;
|
||||||
|
import org.bouncycastle.jce.ECNamedCurveTable;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.math.ec.ECCurve;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: KeXue
|
||||||
|
* @time: 2022/8/25
|
||||||
|
* @description: SM2加解密工具类
|
||||||
|
*/
|
||||||
|
public class SM2Util {
|
||||||
|
|
||||||
|
private SM2Util() {
|
||||||
|
throw new IllegalStateException("Utility class");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用静态代码块来注册Bouncy Castle Provider
|
||||||
|
// 这段代码会在类第一次被加载时自动执行
|
||||||
|
// static {
|
||||||
|
// if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
|
||||||
|
// Security.addProvider(new BouncyCastleProvider());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
private static final String STD_NAME = "sm2p256v1";
|
||||||
|
|
||||||
|
// private static final Logger log = LoggerFactory.getLogger(SM2Util.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM2加密算法
|
||||||
|
*
|
||||||
|
* @param publicKey 公钥
|
||||||
|
* @param data 明文数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(String publicKey, byte[] data) {
|
||||||
|
ECPublicKeyParameters ecPublicKeyParameters = encodePublicKey(Hex.decode(publicKey));
|
||||||
|
SM2Engine engine = new SM2Engine();
|
||||||
|
engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
|
||||||
|
|
||||||
|
byte[] bytes = null;
|
||||||
|
try {
|
||||||
|
byte[] cipherText = engine.processBlock(data, 0, data.length);
|
||||||
|
bytes = C1C2C3ToC1C3C2(cipherText);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// log.warn("SM2加密时出现异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM2解密算法
|
||||||
|
*
|
||||||
|
* @param privateKey 私钥
|
||||||
|
* @param cipherData 密文数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] decrypt(String privateKey, byte[] cipherData) {
|
||||||
|
ECPrivateKeyParameters ecPrivateKeyParameters = encodePrivateKey(Hex.decode(privateKey));
|
||||||
|
SM2Engine engine = new SM2Engine();
|
||||||
|
engine.init(false, ecPrivateKeyParameters);
|
||||||
|
|
||||||
|
byte[] bytes = null;
|
||||||
|
try {
|
||||||
|
cipherData = C1C3C2ToC1C2C3(cipherData);
|
||||||
|
bytes = engine.processBlock(cipherData, 0, cipherData.length);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// log.warn("SM2解密时出现异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名算法
|
||||||
|
*
|
||||||
|
* @param privateKey 私钥
|
||||||
|
* @param data 明文数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] sign(String privateKey, byte[] data) {
|
||||||
|
ECPrivateKeyParameters ecPrivateKeyParameters = encodePrivateKey(hexToByte(privateKey));
|
||||||
|
SM2Signer signer = new SM2Signer();
|
||||||
|
ParametersWithID parameters = new ParametersWithID(ecPrivateKeyParameters, "1234567812345678".getBytes());
|
||||||
|
signer.init(true, parameters);
|
||||||
|
signer.update(data, 0, data.length);
|
||||||
|
|
||||||
|
byte[] signature = null;
|
||||||
|
try {
|
||||||
|
signature = decodeDERSignature(signer.generateSignature());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// log.warn("SM2签名时出现异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] hexToByte(String hex) throws IllegalArgumentException {
|
||||||
|
if (hex.length() % 2 != 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
char[] arr = hex.toCharArray();
|
||||||
|
byte[] b = new byte[hex.length() / 2];
|
||||||
|
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
|
||||||
|
String swap = "" + arr[i++] + arr[i];
|
||||||
|
int byteInt = Integer.parseInt(swap, 16) & 0xFF;
|
||||||
|
b[j] = BigInteger.valueOf(byteInt).byteValue();
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] C1C2C3ToC1C3C2(byte[] cipherText) throws Exception {
|
||||||
|
if (cipherText != null && cipherText.length >= 97) {
|
||||||
|
byte[] bytes = new byte[cipherText.length];
|
||||||
|
System.arraycopy(cipherText, 0, bytes, 0, 65);
|
||||||
|
System.arraycopy(cipherText, cipherText.length - 32, bytes, 65, 32);
|
||||||
|
System.arraycopy(cipherText, 65, bytes, 97, cipherText.length - 97);
|
||||||
|
return bytes;
|
||||||
|
} else {
|
||||||
|
throw new Exception("SM2 cipher text error, must be more than 96 bytes and in the format C1||C3||C2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] C1C3C2ToC1C2C3(byte[] cipherText) throws Exception {
|
||||||
|
if (cipherText != null && cipherText.length >= 97) {
|
||||||
|
byte[] bytes = new byte[cipherText.length];
|
||||||
|
System.arraycopy(cipherText, 0, bytes, 0, 65);
|
||||||
|
System.arraycopy(cipherText, 97, bytes, 65, cipherText.length - 97);
|
||||||
|
System.arraycopy(cipherText, 65, bytes, cipherText.length - 32, 32);
|
||||||
|
return bytes;
|
||||||
|
} else {
|
||||||
|
throw new Exception("SM2 cipher text error, must be more than 96 bytes and in the format C1||C3||C2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECPublicKeyParameters encodePublicKey(byte[] value) {
|
||||||
|
byte[] x = new byte[32];
|
||||||
|
byte[] y = new byte[32];
|
||||||
|
System.arraycopy(value, 1, x, 0, 32);
|
||||||
|
System.arraycopy(value, 33, y, 0, 32);
|
||||||
|
BigInteger X = new BigInteger(1, x);
|
||||||
|
BigInteger Y = new BigInteger(1, y);
|
||||||
|
ECPoint Q = getSM2Curve().createPoint(X, Y);
|
||||||
|
return new ECPublicKeyParameters(Q, getECDomainParameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECCurve getSM2Curve() {
|
||||||
|
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(STD_NAME);
|
||||||
|
return spec.getCurve();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECPrivateKeyParameters encodePrivateKey(byte[] value) {
|
||||||
|
BigInteger d = new BigInteger(1, value);
|
||||||
|
return new ECPrivateKeyParameters(d, getECDomainParameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECDomainParameters getECDomainParameters() {
|
||||||
|
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(STD_NAME);
|
||||||
|
return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] decodeDERSignature(byte[] signature) {
|
||||||
|
ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
|
||||||
|
|
||||||
|
byte[] bytes = new byte[64];
|
||||||
|
try {
|
||||||
|
ASN1Sequence primitive = (ASN1Sequence) stream.readObject();
|
||||||
|
Enumeration enumeration = primitive.getObjects();
|
||||||
|
BigInteger R = ((ASN1Integer) enumeration.nextElement()).getValue();
|
||||||
|
BigInteger S = ((ASN1Integer) enumeration.nextElement()).getValue();
|
||||||
|
byte[] r = format(R.toByteArray());
|
||||||
|
byte[] s = format(S.toByteArray());
|
||||||
|
System.arraycopy(r, 0, bytes, 0, 32);
|
||||||
|
System.arraycopy(s, 0, bytes, 32, 32);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// log.warn("decodeDERSignature时出现异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encodeDERSignature(byte[] signature) {
|
||||||
|
byte[] r = new byte[32];
|
||||||
|
byte[] s = new byte[32];
|
||||||
|
System.arraycopy(signature, 0, r, 0, 32);
|
||||||
|
System.arraycopy(signature, 32, s, 0, 32);
|
||||||
|
ASN1EncodableVector vector = new ASN1EncodableVector();
|
||||||
|
vector.add(new ASN1Integer(new BigInteger(1, r)));
|
||||||
|
vector.add(new ASN1Integer(new BigInteger(1, s)));
|
||||||
|
|
||||||
|
byte[] encoded = null;
|
||||||
|
try {
|
||||||
|
encoded = (new DERSequence(vector)).getEncoded();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// log.warn("encodeDERSignature时出现异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] format(byte[] value) {
|
||||||
|
if (value.length == 32) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
byte[] bytes = new byte[32];
|
||||||
|
if (value.length > 32) {
|
||||||
|
System.arraycopy(value, value.length - 32, bytes, 0, 32);
|
||||||
|
} else {
|
||||||
|
System.arraycopy(value, 0, bytes, 32 - value.length, value.length);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
# contributor license agreements. See the NOTICE file distributed with
|
||||||
|
# this work for additional information regarding copyright ownership.
|
||||||
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
# (the "License"); you may not use this file except in compliance with
|
||||||
|
# the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
com.hzya.frame.ZsyhCbs
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.hzya.frame.util;
|
||||||
|
|
||||||
|
//import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||||
|
//import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.jce.ECNamedCurveTable;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:liuyang
|
||||||
|
* @Package:com.hzya.frame.util
|
||||||
|
* @Project:nifi-hzyadev-bundle
|
||||||
|
* @name:BCTest
|
||||||
|
* @Date:2025/9/9 16:12
|
||||||
|
* @Filename:BCTest
|
||||||
|
*/
|
||||||
|
public class BCTest {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("开始测试Bouncy Castle环境...");
|
||||||
|
|
||||||
|
// 1. 尝试注册Provider
|
||||||
|
// try {
|
||||||
|
// Security.addProvider(new BouncyCastleProvider());
|
||||||
|
// System.out.println("Bouncy Castle Provider 注册成功!Provider列表大小: " + Security.getProviders().length);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// System.err.println("!!! Bouncy Castle Provider 注册失败 !!!");
|
||||||
|
// e.printStackTrace();
|
||||||
|
// return; // 注册失败,直接退出
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 2. 尝试获取曲线参数
|
||||||
|
String curveName = "sm2p256v1";
|
||||||
|
System.out.println("正在尝试获取曲线 '" + curveName + "' 的参数...");
|
||||||
|
ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveName);
|
||||||
|
|
||||||
|
// 3. 检查结果
|
||||||
|
if (spec != null) {
|
||||||
|
System.out.println("✅ 成功获取到曲线 '" + curveName + "' 的参数!spec对象不是null。");
|
||||||
|
} else {
|
||||||
|
System.err.println("❌ 获取曲线 '" + curveName + "' 的参数失败!spec对象为null。");
|
||||||
|
}
|
||||||
|
|
||||||
|
// X9ECParameters params = GMNamedCurves.getByName(curveName);
|
||||||
|
// System.out.println(params);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
//package com.hzya.frame.util;
|
||||||
|
//
|
||||||
|
//import org.junit.Test;
|
||||||
|
//
|
||||||
|
//import static org.junit.Assert.*;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * @Author:liuyang
|
||||||
|
// * @Package:com.hzya.frame.util
|
||||||
|
// * @Project:nifi-hzyadev-bundle
|
||||||
|
// * @name:CbsUtilTest
|
||||||
|
// * @Date:2025/9/9 14:51
|
||||||
|
// * @Filename:CbsUtilTest
|
||||||
|
// */
|
||||||
|
//public class CbsUtilTest {
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void getCbsData() {
|
||||||
|
// String uri = "/openapi/draft2/openapi/v2/trsinfo/query-trs-info-page";
|
||||||
|
// String reqBody = "{\n" +
|
||||||
|
// "\t\"applyDateStart\":\"2025-08-01\",\n" +
|
||||||
|
// "\t\"applyDateEnd\":\"2025-08-31\",\n" +
|
||||||
|
// "\t\"initAccountList\":\"591915131310106\"\n" +
|
||||||
|
// "}";
|
||||||
|
//
|
||||||
|
// CbsUtil.getCbsData(uri, reqBody);
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,43 @@
|
||||||
|
//package com.hzya.frame.util;
|
||||||
|
//
|
||||||
|
//import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
//import org.apache.http.client.methods.HttpPost;
|
||||||
|
//import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
//import org.apache.http.impl.client.HttpClients;
|
||||||
|
//import org.junit.Test;
|
||||||
|
//
|
||||||
|
//import java.io.IOException;
|
||||||
|
//
|
||||||
|
//import static org.junit.Assert.*;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * @Author:liuyang
|
||||||
|
// * @Package:com.hzya.frame.util
|
||||||
|
// * @Project:nifi-hzyadev-bundle
|
||||||
|
// * @name:SM2ExampleTest
|
||||||
|
// * @Date:2025/9/9 15:14
|
||||||
|
// * @Filename:SM2ExampleTest
|
||||||
|
// */
|
||||||
|
//public class SM2ExampleTest {
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// public void test1() {
|
||||||
|
// try {
|
||||||
|
// SM2Example sm2Example = new SM2Example();
|
||||||
|
//
|
||||||
|
// CloseableHttpClient client = HttpClients.custom().disableContentCompression().build();
|
||||||
|
//
|
||||||
|
// HttpPost httpPost = sm2Example.setupRequest();
|
||||||
|
// try (CloseableHttpResponse response = client.execute(httpPost)) {
|
||||||
|
// byte[] finalResponseData = sm2Example.handleResponse(response);
|
||||||
|
// System.out.println(new String(finalResponseData));
|
||||||
|
// } catch (IOException ignored) {
|
||||||
|
// throw new IOException("网络连接失败或超时!");
|
||||||
|
// } finally {
|
||||||
|
// client.close();
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -27,6 +27,8 @@
|
||||||
<module>hzya-nifi-AutoAddOracleDatafile-processors</module>
|
<module>hzya-nifi-AutoAddOracleDatafile-processors</module>
|
||||||
<module>hzya-nifi-Zjnx-czb-processors</module>
|
<module>hzya-nifi-Zjnx-czb-processors</module>
|
||||||
<module>hzya-nifi-Zjnx-czb-nar</module>
|
<module>hzya-nifi-Zjnx-czb-nar</module>
|
||||||
|
<module>hzya-nifi-Zsyh-cbs-nar</module>
|
||||||
|
<module>hzya-nifi-Zsyh-cbs-processors</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
|
Loading…
Reference in New Issue