From 3699d0b6e58381f2ab4e4f077ef2f9548085ee18 Mon Sep 17 00:00:00 2001
From: liuy <37787198+LiuyCodes@users.noreply.github.com>
Date: Tue, 9 Sep 2025 16:49:27 +0800
Subject: [PATCH] =?UTF-8?q?feat(nifi):=20=E6=B7=BB=E5=8A=A0=E6=8B=9B?=
=?UTF-8?q?=E5=95=86=E9=93=B6=E8=A1=8CCBS=E6=8E=A5=E5=8F=A3=E8=B0=83?=
=?UTF-8?q?=E7=94=A8=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 hzya-nifi-Zsyh-cbs-nar 和 hzya-nifi-Zsyh-cbs-processors 模块
- 实现了与招商银行CBS系统交互的常量类、工具类和处理器
- 添加了SM2加密解密功能
- 集成了Bouncy Castle加密库
-编写了单元测试用例
---
.../hzya-nifi-Zsyh-cbs-nar/pom.xml | 34 +++
.../hzya-nifi-Zsyh-cbs-processors/pom.xml | 97 ++++++++
.../src/main/java/com/hzya/frame/ZsyhCbs.java | 12 +
.../java/com/hzya/frame/util/Constants.java | 23 ++
.../java/com/hzya/frame/util/SM2Example.java | 161 +++++++++++++
.../java/com/hzya/frame/util/SM2Util.java | 228 ++++++++++++++++++
.../org.apache.nifi.processor.Processor | 15 ++
.../test/java/com/hzya/frame/util/BCTest.java | 50 ++++
.../java/com/hzya/frame/util/CbsUtilTest.java | 28 +++
.../com/hzya/frame/util/SM2ExampleTest.java | 43 ++++
nifi-hzyadev-bundle/pom.xml | 2 +
11 files changed, 693 insertions(+)
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-nar/pom.xml
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/pom.xml
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/ZsyhCbs.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/Constants.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Example.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Util.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/BCTest.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/CbsUtilTest.java
create mode 100644 nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/SM2ExampleTest.java
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-nar/pom.xml b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-nar/pom.xml
new file mode 100644
index 0000000..b76d4e0
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-nar/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ nifi-hzyadev-bundle
+ com.hzya
+ 1.0
+
+ 4.0.0
+
+ hzya-nifi-Zsyh-cbs-nar
+
+ nar
+
+
+ 8
+ 8
+
+
+
+
+ com.hzya
+ hzya-nifi-Zjnx-czb-processors
+ 1.0
+
+
+ org.apache.nifi
+ nifi-standard-services-api-nar
+ ${nifi-revision}
+ nar
+
+
+
\ No newline at end of file
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/pom.xml b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/pom.xml
new file mode 100644
index 0000000..9eb5b51
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/pom.xml
@@ -0,0 +1,97 @@
+
+
+
+ nifi-hzyadev-bundle
+ com.hzya
+ 1.0
+
+ 4.0.0
+
+ hzya-nifi-Zsyh-cbs-processors
+
+
+ 8
+ 8
+
+
+
+
+ org.apache.nifi
+ nifi-api
+ ${nifi-revision}
+
+
+ org.apache.nifi
+ nifi-dbcp-service-api
+ ${nifi-revision}
+
+
+ org.apache.nifi
+ nifi-processor-utils
+ 1.15.3
+
+
+ org.apache.nifi
+ nifi-mock
+ ${nifi-revision}
+ test
+
+
+ junit
+ junit
+ 4.13
+ test
+
+
+ com.squareup.okhttp3
+ mockwebserver
+ 4.9.3
+ test
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+ org.bouncycastle
+ bcprov-jdk18on
+ 1.78.1
+
+
+
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.36
+
+
+
+
+
+
+
+
+
+ org.slf4j
+ slf4j-simple
+ 1.7.36
+
+
+ commons-logging
+ commons-logging
+ 1.2
+
+
+
\ No newline at end of file
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/ZsyhCbs.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/ZsyhCbs.java
new file mode 100644
index 0000000..8c28db8
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/ZsyhCbs.java
@@ -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 {
+}
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/Constants.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/Constants.java
new file mode 100644
index 0000000..f938330
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/Constants.java
@@ -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 ";
+}
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Example.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Example.java
new file mode 100644
index 0000000..e984d60
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Example.java
@@ -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);
+ }
+}
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Util.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Util.java
new file mode 100644
index 0000000..8c46344
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/java/com/hzya/frame/util/SM2Util.java
@@ -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;
+ }
+ }
+}
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
new file mode 100644
index 0000000..22938e5
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
@@ -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
\ No newline at end of file
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/BCTest.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/BCTest.java
new file mode 100644
index 0000000..84a9047
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/BCTest.java
@@ -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);
+ }
+}
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/CbsUtilTest.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/CbsUtilTest.java
new file mode 100644
index 0000000..601cc4d
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/CbsUtilTest.java
@@ -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);
+// }
+//}
\ No newline at end of file
diff --git a/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/SM2ExampleTest.java b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/SM2ExampleTest.java
new file mode 100644
index 0000000..3c816cd
--- /dev/null
+++ b/nifi-hzyadev-bundle/hzya-nifi-Zsyh-cbs-processors/src/test/java/com/hzya/frame/util/SM2ExampleTest.java
@@ -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();
+// }
+// }
+//}
\ No newline at end of file
diff --git a/nifi-hzyadev-bundle/pom.xml b/nifi-hzyadev-bundle/pom.xml
index cbdaf5b..acd3c9d 100644
--- a/nifi-hzyadev-bundle/pom.xml
+++ b/nifi-hzyadev-bundle/pom.xml
@@ -27,6 +27,8 @@
hzya-nifi-AutoAddOracleDatafile-processors
hzya-nifi-Zjnx-czb-processors
hzya-nifi-Zjnx-czb-nar
+ hzya-nifi-Zsyh-cbs-nar
+ hzya-nifi-Zsyh-cbs-processors