From 726f38c332e2afffae525e49f0d277b3c6d83469 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 7 Nov 2023 10:43:26 +0800
Subject: [PATCH 1/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0SM2=E3=80=81SM4=E7=9A=84?=
=?UTF-8?q?=E7=94=9F=E6=88=90=E5=AF=86=E9=92=A5=E5=92=8C=E5=8A=A0=E8=A7=A3?=
=?UTF-8?q?=E5=AF=86=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
neutrino-proxy-core/pom.xml | 11 ++
.../core/util/SmEncryptUtil.java | 103 ++++++++++++++++++
pom.xml | 2 +-
3 files changed, 115 insertions(+), 1 deletion(-)
create mode 100644 neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
diff --git a/neutrino-proxy-core/pom.xml b/neutrino-proxy-core/pom.xml
index fc566dbf..8ba6da84 100644
--- a/neutrino-proxy-core/pom.xml
+++ b/neutrino-proxy-core/pom.xml
@@ -24,12 +24,23 @@
io.netty
netty-all
+
+
+ org.bouncycastle
+ bcprov-jdk15to18
+
+
cn.hutool
hutool-core
${hutool.version}
+
+ cn.hutool
+ hutool-crypto
+ ${hutool.version}
+
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
new file mode 100644
index 00000000..8bf5ab86
--- /dev/null
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2022 aoshiguchen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.dromara.neutrinoproxy.core.util;
+
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.SmUtil;
+import lombok.Data;
+
+import javax.crypto.SecretKey;
+import java.security.KeyPair;
+
+/**
+ * 国密算法加解密工具
+ * @author: az
+ * @date: 2023/11/07
+ */
+public class SmEncryptUtil {
+
+ record Sm2KeyPairRecord(String privateKey, String publicKey) {
+ }
+
+ /**
+ * 生成SM2密钥对
+ * @return
+ */
+ public static Sm2KeyPairRecord generateSm2KeyPair() {
+ KeyPair keyPair = SecureUtil.generateKeyPair("SM2");
+ byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
+ byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
+
+ String privateKey = HexUtil.encodeHexStr(privateKeyBytes);
+ String publicKey = HexUtil.encodeHexStr(publicKeyBytes);
+
+ return new Sm2KeyPairRecord(privateKey, publicKey);
+ }
+
+ /**
+ * 使用SM2算法对数据进行加密
+ * @param publicKey 加密所需的公钥
+ * @param data 需要加密的数据
+ * @return 加密后的字节数组
+ */
+ public static byte[] encryptBySm2(String publicKey, byte[] data) {
+ return SmUtil.sm2(null, publicKey).encrypt(data);
+ }
+
+ /**
+ * 使用SM2算法对数据进行解密
+ * @param privateKey 解密所需私钥
+ * @param data 需要解密的数据
+ * @return 解密后的字节数组
+ */
+ public static byte[] decryptBySm2(String privateKey, byte[] data) {
+ return SmUtil.sm2(privateKey, null).decrypt(data);
+ }
+
+ public static byte[] generateSm4Key() {
+ SecretKey key = SecureUtil.generateKey("AES", 128);
+ return key.getEncoded();
+ }
+
+ /**
+ * 使用SM4算法加密数据
+ * @param key 密钥
+ * @param data 待加密的数据
+ * @return 已加密的数据
+ */
+ public static byte[] encryptBySm4(byte[] key, byte[] data) {
+ return SmUtil.sm4(key).encrypt(data);
+ }
+
+ /**
+ * 使用SM4算法解密数据
+ * @param key 密钥
+ * @param encryptedData 已加密数据
+ * @return 解密后的数据
+ */
+ public static byte[] decryptBySm4(byte[] key, byte[] encryptedData) {
+ return SmUtil.sm4(key).decrypt(encryptedData);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index a5bbabfa..28237270 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1 +1 @@
-
4.0.0
org.noear
solon-parent
2.5.12
org.dromara.neutrino-proxy
neutrino-proxy
pom
${revision}
neutrino-proxy-core
neutrino-proxy-client
neutrino-proxy-server
UTF-8
UTF-8
UTF-8
2.0.1-SNAPSHOT
0.9.28
21
3.8.0
1.1.0
io.netty
netty-all
4.1.100.Final
org.yaml
snakeyaml
1.33
junit
junit
4.12
test
org.apache.commons
commons-lang3
3.9
com.google.guava
guava
28.0-jre
commons-fileupload
commons-fileupload
1.3.1
com.h2database
h2
2.2.224
mysql
mysql-connector-java
8.0.33
org.mariadb.jdbc
mariadb-java-client
2.7.4
com.zaxxer
HikariCP
4.0.3
org.dromara.solon-plugins
job-solon-plugin
0.1.1
cn.hutool
hutool-core
org.noear
solon.logging.logback
org.projectlombok
lombok
provided
org.apache.commons
commons-lang3
com.google.guava
guava
org.noear
solon-test
test
src/main/resources
org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
${java.version}
${java.version}
UTF-8
org.projectlombok
lombok
${lombok.version}
org.codehaus.mojo
flatten-maven-plugin
${maven-flatten.version}
true
resolveCiFriendliesOnly
flatten
process-resources
flatten
flatten.clean
clean
clean
tencent
https://mirrors.cloud.tencent.com/nexus/repository/maven-public/
false
sonatype-nexus-snapshots
Sonatype Nexus Snapshots
https://oss.sonatype.org/content/repositories/snapshots
false
sonatype-nexus-snapshots
Sonatype Nexus Snapshots
https://oss.sonatype.org/content/repositories/snapshots
false
native
org.noear
solon-maven-plugin
${solon.version}
process-aot
process-aot
org.codehaus.plexus
plexus-utils
3.5.1
org.graalvm.buildtools
native-maven-plugin
${native.version}
true
add-reachability-metadata
add-reachability-metadata
\ No newline at end of file
+
4.0.0
org.noear
solon-parent
2.5.12
org.dromara.neutrino-proxy
neutrino-proxy
pom
${revision}
neutrino-proxy-core
neutrino-proxy-client
neutrino-proxy-server
UTF-8
UTF-8
UTF-8
2.0.1-SNAPSHOT
0.9.28
21
3.8.0
1.1.0
io.netty
netty-all
4.1.100.Final
org.yaml
snakeyaml
1.33
junit
junit
4.12
test
org.apache.commons
commons-lang3
3.9
com.google.guava
guava
28.0-jre
commons-fileupload
commons-fileupload
1.3.1
com.h2database
h2
2.2.224
mysql
mysql-connector-java
8.0.33
org.mariadb.jdbc
mariadb-java-client
2.7.4
com.zaxxer
HikariCP
4.0.3
org.bouncycastle
bcprov-jdk15to18
1.69
org.dromara.solon-plugins
job-solon-plugin
0.1.1
cn.hutool
hutool-core
org.noear
solon.logging.logback
org.projectlombok
lombok
provided
org.apache.commons
commons-lang3
com.google.guava
guava
org.noear
solon-test
test
src/main/resources
org.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
${java.version}
${java.version}
UTF-8
org.projectlombok
lombok
${lombok.version}
org.codehaus.mojo
flatten-maven-plugin
${maven-flatten.version}
true
resolveCiFriendliesOnly
flatten
process-resources
flatten
flatten.clean
clean
clean
tencent
https://mirrors.cloud.tencent.com/nexus/repository/maven-public/
false
sonatype-nexus-snapshots
Sonatype Nexus Snapshots
https://oss.sonatype.org/content/repositories/snapshots
false
sonatype-nexus-snapshots
Sonatype Nexus Snapshots
https://oss.sonatype.org/content/repositories/snapshots
false
native
org.noear
solon-maven-plugin
${solon.version}
process-aot
process-aot
org.codehaus.plexus
plexus-utils
3.5.1
org.graalvm.buildtools
native-maven-plugin
${native.version}
true
add-reachability-metadata
add-reachability-metadata
\ No newline at end of file
From a16fba4b03ee85e62f4350a81cdf16ad5e16013a Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 7 Nov 2023 15:25:41 +0800
Subject: [PATCH 2/6] =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8D=8F=E5=95=86?=
=?UTF-8?q?=E8=BF=87=E7=A8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../handler/ProxyMessageAuthHandler.java | 14 ++++
.../handler/ProxyMessageSecureKeyHandler.java | 30 +++++++++
.../dromara/neutrinoproxy/core/Constants.java | 5 ++
.../neutrinoproxy/core/KeyPairRecord.java | 31 +++++++++
.../neutrinoproxy/core/ProxyDataTypeEnum.java | 4 +-
.../neutrinoproxy/core/ProxyMessage.java | 20 +++++-
.../core/util/SmEncryptUtil.java | 18 +++--
.../handler/ProxyMessageAuthHandler.java | 23 +++++--
.../handler/ProxyMessageSecureKeyHandler.java | 65 +++++++++++++++++++
9 files changed, 195 insertions(+), 15 deletions(-)
create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
create mode 100644 neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/KeyPairRecord.java
create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
index ff41bc10..672576aa 100644
--- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
@@ -1,6 +1,7 @@
package org.dromara.neutrinoproxy.client.handler;
import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.Attribute;
import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
import org.dromara.neutrinoproxy.core.Constants;
@@ -8,6 +9,7 @@ import org.dromara.neutrinoproxy.core.ExceptionEnum;
import org.dromara.neutrinoproxy.core.ProxyMessage;
import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
import org.dromara.neutrinoproxy.core.dispatcher.Match;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
import org.noear.snack.ONode;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
@@ -42,5 +44,17 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
){
context.channel().close();
}
+
+ // 获取认证成功的后的公钥信息,并生成随机密码,加密发到服务端确认
+ String publicKey = load.get("publicKey").getString();
+ byte[] secureKey = SmEncryptUtil.generateSm4Key();
+ // 存储密码
+ Attribute secureKeyAttr = context.attr(Constants.SECURE_KEY);
+ secureKeyAttr.set(secureKey);
+
+ // 使用SM2算法对密钥进行加密并发送到服务端
+ byte[] encryptSecureKey = SmEncryptUtil.encryptBySm2(publicKey, secureKey);
+ context.writeAndFlush(ProxyMessage.buildSecureKeyMessage(encryptSecureKey));
+ context.flush();
}
}
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
new file mode 100644
index 00000000..05a5361e
--- /dev/null
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
@@ -0,0 +1,30 @@
+package org.dromara.neutrinoproxy.client.handler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.Attribute;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.neutrinoproxy.core.Constants;
+import org.dromara.neutrinoproxy.core.ProxyMessage;
+import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
+import org.dromara.neutrinoproxy.core.dispatcher.Match;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
+import org.noear.solon.annotation.Component;
+
+@Slf4j
+@Match(type = Constants.ProxyDataTypeName.SECURE_KEY)
+@Component
+public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
+ @Override
+ public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
+ Attribute secureKeyAttr = ctx.attr(Constants.SECURE_KEY);
+ byte[] secureKey = secureKeyAttr.get();
+ byte[] data = proxyMessage.getData();
+ byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, data);
+ String m = new String(decryptedData);
+ if ("ok".equals(m)) {
+ log.info("Successfully established encrypted link");
+ } else {
+ ctx.channel().close();
+ }
+ }
+}
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
index 472f8ce9..ab831211 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
@@ -38,6 +38,10 @@ public interface Constants {
AttributeKey VISITOR_ID = AttributeKey.newInstance("visitor_id");
+ AttributeKey SECURE_PRIVATE_KEY = AttributeKey.newInstance("secure_private_key");
+
+ AttributeKey SECURE_KEY = AttributeKey.newInstance("secure_key");
+
AttributeKey LICENSE_ID = AttributeKey.newInstance("license_id");
AttributeKey TARGET_IP = AttributeKey.newInstance("targetIp");
@@ -57,6 +61,7 @@ public interface Constants {
interface ProxyDataTypeName {
String HEARTBEAT = "HEARTBEAT";
+ String SECURE_KEY = "SECURE_KEY";
String AUTH = "AUTH";
String CONNECT = "CONNECT";
String DISCONNECT = "DISCONNECT";
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/KeyPairRecord.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/KeyPairRecord.java
new file mode 100644
index 00000000..4826047d
--- /dev/null
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/KeyPairRecord.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2022 aoshiguchen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.dromara.neutrinoproxy.core;
+
+/**
+ * 存储公钥和私钥
+ * @param privateKey
+ * @param publicKey
+ */
+public record KeyPairRecord(String privateKey, String publicKey) {
+}
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java
index e533bf8e..4c30d888 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java
@@ -47,7 +47,9 @@ public enum ProxyDataTypeEnum {
PORT_MAPPING_SYNC(0x07, Constants.ProxyDataTypeName.PORT_MAPPING_SYNC, "PORT_MAPPING_SYNC"),
UDP_CONNECT(0x08, Constants.ProxyDataTypeName.UDP_CONNECT,"UDP_CONNECT"),
UDP_DISCONNECT(0x09, Constants.ProxyDataTypeName.UDP_DISCONNECT,"UDP_DISCONNECT"),
- UDP_TRANSFER(0x10, Constants.ProxyDataTypeName.UDP_TRANSFER,"UDP_TRANSFER");
+ UDP_TRANSFER(0x10, Constants.ProxyDataTypeName.UDP_TRANSFER,"UDP_TRANSFER"),
+ SECURE_KEY(0x11, Constants.ProxyDataTypeName.SECURE_KEY, "SECURE_KEY"),
+ ;
private static Map cache = Stream.of(values()).collect(Collectors.toMap(ProxyDataTypeEnum::getType, Function.identity()));
private int type;
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java
index 78de8f56..0da050fe 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java
@@ -24,6 +24,7 @@ package org.dromara.neutrinoproxy.core;
import lombok.Data;
import lombok.experimental.Accessors;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
import org.noear.snack.ONode;
import java.util.Arrays;
@@ -79,6 +80,11 @@ public class ProxyMessage {
*/
public static final byte TYPE_UDP_TRANSFER = 0x10;
+ /**
+ * 安全密钥协商
+ */
+ public static final byte TYPE_SECURE_KEY = 0x11;
+
/**
* 消息类型
*/
@@ -117,11 +123,12 @@ public class ProxyMessage {
.setInfo(info + "," + clientId);
}
- public static ProxyMessage buildAuthResultMessage(Integer code, String msg, String licenseKey) {
+ public static ProxyMessage buildAuthResultMessage(Integer code, String msg, String licenseKey, String publicKey) {
ONode data = ONode.newObject();
data.set("code", code);
data.set("msg", msg);
data.set("licenseKey", licenseKey);
+ data.set("publicKey", publicKey);
return create().setType(TYPE_AUTH)
.setInfo(data.toJson());
}
@@ -136,6 +143,17 @@ public class ProxyMessage {
.setInfo(info);
}
+ public static ProxyMessage buildSecureKeyMessage(byte[] secureKey) {
+ return create().setType(TYPE_SECURE_KEY)
+ .setInfo(SmEncryptUtil.digestBySm3(secureKey))
+ .setData(secureKey);
+ }
+
+ public static ProxyMessage buildSecureKeyReturnMessage(byte[] content) {
+ return create().setType(TYPE_SECURE_KEY)
+ .setData(content);
+ }
+
public static ProxyMessage buildTransferMessage(String visitorId, byte[] data) {
return create().setType(TYPE_TRANSFER)
.setInfo(visitorId)
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
index 8bf5ab86..10c67de4 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/util/SmEncryptUtil.java
@@ -25,7 +25,7 @@ package org.dromara.neutrinoproxy.core.util;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
-import lombok.Data;
+import org.dromara.neutrinoproxy.core.KeyPairRecord;
import javax.crypto.SecretKey;
import java.security.KeyPair;
@@ -37,14 +37,11 @@ import java.security.KeyPair;
*/
public class SmEncryptUtil {
- record Sm2KeyPairRecord(String privateKey, String publicKey) {
- }
-
/**
* 生成SM2密钥对
* @return
*/
- public static Sm2KeyPairRecord generateSm2KeyPair() {
+ public static KeyPairRecord generateSm2KeyPair() {
KeyPair keyPair = SecureUtil.generateKeyPair("SM2");
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
@@ -52,7 +49,7 @@ public class SmEncryptUtil {
String privateKey = HexUtil.encodeHexStr(privateKeyBytes);
String publicKey = HexUtil.encodeHexStr(publicKeyBytes);
- return new Sm2KeyPairRecord(privateKey, publicKey);
+ return new KeyPairRecord(privateKey, publicKey);
}
/**
@@ -100,4 +97,13 @@ public class SmEncryptUtil {
return SmUtil.sm4(key).decrypt(encryptedData);
}
+ /**
+ * 使用SM3算法对内容生成摘要
+ * @param data
+ * @return
+ */
+ public static String digestBySm3(byte[] data) {
+ return SmUtil.sm3().digestHex(data);
+ }
+
}
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
index 2fc7a678..bc33dedd 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
@@ -23,9 +23,10 @@
package org.dromara.neutrinoproxy.server.proxy.handler;
import cn.hutool.core.util.StrUtil;
-import org.dromara.neutrinoproxy.core.*;
+import io.netty.util.Attribute;
import org.dromara.neutrinoproxy.core.*;
import org.dromara.neutrinoproxy.core.dispatcher.Match;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
import org.dromara.neutrinoproxy.server.constant.ClientConnectTypeEnum;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
@@ -90,7 +91,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
if (StrUtil.isEmpty(licenseKey)) {
log.warn("[client connection] license cannot empty info:{} ", info);
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -105,7 +106,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
LicenseDO licenseDO = licenseService.findByKey(licenseKey);
if (null == licenseDO) {
log.warn("[client connection] license notfound info:{} ", info);
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -119,7 +120,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
}
if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) {
log.warn("[client connection] the license disabled info:{} ", info);
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license disabled!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license disabled!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -134,7 +135,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
UserDO userDO = userService.findById(licenseDO.getUserId());
if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
log.warn("[client connection] the license invalid info:{} ", info);
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license invalid!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license invalid!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -151,7 +152,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
String _clientId = ProxyUtil.getClientIdByLicenseId(licenseDO.getId());
if (!clientId.equals(_clientId)) {
log.warn("[client connection] the license on another no used info:{} _clientId:{}", info, _clientId);
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license on another no used!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license on another no used!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
@@ -164,8 +165,16 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
return;
}
}
+
+ // 生成获取SM2密钥对,私钥存入ctx,公钥拼装参数随Auth数据包返回
+ KeyPairRecord record = SmEncryptUtil.generateSm2KeyPair();
+
+ // 私钥存入ctx
+ Attribute attr = ctx.attr(Constants.SECURE_PRIVATE_KEY);
+ attr.setIfAbsent(record.privateKey());
+
// 发送认证成功消息
- ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "auth success!", licenseKey));
+ ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "auth success!", licenseKey, record.publicKey()));
clientConnectRecordService.add(new ClientConnectRecordDO()
.setIp(ip)
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
new file mode 100644
index 00000000..587d548a
--- /dev/null
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
@@ -0,0 +1,65 @@
+package org.dromara.neutrinoproxy.server.proxy.handler;
+
+import cn.hutool.core.util.StrUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.Attribute;
+import io.netty.util.AttributeKey;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.neutrinoproxy.core.Constants;
+import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum;
+import org.dromara.neutrinoproxy.core.ProxyMessage;
+import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
+import org.dromara.neutrinoproxy.core.dispatcher.Match;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
+import org.noear.solon.annotation.Component;
+
+@Slf4j
+@Match(type= Constants.ProxyDataTypeName.SECURE_KEY)
+@Component
+public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
+
+ @Override
+ public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
+
+ // data为加密后的密码,info为加密密码的摘要
+ byte[] data = proxyMessage.getData();
+ String receivedDigest = proxyMessage.getInfo();
+
+ String digest = SmEncryptUtil.digestBySm3(data);
+ if (!digest.equals(receivedDigest)) {
+ // 获取加密信息失败
+ log.warn("密码协商失败");
+ // TODO 应该断开连接
+ return;
+ }
+
+ // 获取私钥
+ Attribute privateKeyAttr = ctx.attr(Constants.SECURE_PRIVATE_KEY);
+ String privateKey = privateKeyAttr.get();
+ if (StrUtil.isEmpty(privateKey)) {
+ // 获取私钥失败
+ log.warn("获取私钥失败");
+ // TODO 应该断开连接
+ return;
+ }
+
+ // 解密传输密码
+ byte[] secureKey = SmEncryptUtil.decryptBySm2(privateKey, data);
+
+ // 传输密码存储ctx中
+ Attribute secureKeyAttr = ctx.attr(Constants.SECURE_KEY);
+ secureKeyAttr.setIfAbsent(secureKey);
+
+ // 使用密码加密success给客户端表示密码已确认
+ byte[] encryptedSuccessInfoData = SmEncryptUtil.encryptBySm4(secureKey, "ok".getBytes());
+
+ // 发送回去,以示确认
+ ctx.writeAndFlush(ProxyMessage.buildSecureKeyReturnMessage(encryptedSuccessInfoData));
+ ctx.flush();
+ }
+
+ @Override
+ public String name() {
+ return ProxyDataTypeEnum.SECURE_KEY.getDesc();
+ }
+}
From 4eb04e6f0ffb45651cbffa958c4d05f0edf6e795 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 7 Nov 2023 16:46:18 +0800
Subject: [PATCH 3/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9encoder=E5=92=8Cdecoder?=
=?UTF-8?q?=E9=80=82=E9=85=8D=E5=8A=A0=E5=AF=86=E8=BF=87=E7=A8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../handler/ProxyMessageSecureKeyHandler.java | 2 +-
.../core/ProxyMessageDecoder.java | 35 ++++++++++++++-----
.../core/ProxyMessageEncoder.java | 34 +++++++++++++-----
3 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
index 05a5361e..09da501c 100644
--- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
@@ -22,7 +22,7 @@ public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, data);
String m = new String(decryptedData);
if ("ok".equals(m)) {
- log.info("Successfully established encrypted link");
+ log.info("Encrypted link established successfully");
} else {
ctx.channel().close();
}
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
index 2729967a..3fa077d9 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
@@ -23,8 +23,12 @@
package org.dromara.neutrinoproxy.core;
import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import io.netty.util.Attribute;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
+
import static org.dromara.neutrinoproxy.core.Constants.*;
/**
@@ -70,28 +74,43 @@ public class ProxyMessageDecoder extends LengthFieldBasedFrameDecoder {
return null;
}
- int frameLength = in.readInt();
- if (in.readableBytes() < frameLength) {
+ int packageLength = in.readInt();
+ if (in.readableBytes() < packageLength) {
return null;
}
+
+ // 获取加密数据
+ byte[] encryptedBytes = new byte[packageLength];
+ in.readBytes(encryptedBytes);
+ in.release();
+
+ // 获取解密密钥
+ Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
+ byte[] secureKey = secureKeyAttr.get();
+ // 解密
+ byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, encryptedBytes);
+
+ ByteBuf buf = Unpooled.wrappedBuffer(decryptedData);
+
ProxyMessage proxyMessage = new ProxyMessage();
- byte type = in.readByte();
- long sn = in.readLong();
+ int frameLength = buf.readInt();
+ byte type = buf.readByte();
+ long sn = buf.readLong();
proxyMessage.setSerialNumber(sn);
proxyMessage.setType(type);
- int infoLength = in.readInt();
+ int infoLength = buf.readInt();
byte[] infoBytes = new byte[infoLength];
- in.readBytes(infoBytes);
+ buf.readBytes(infoBytes);
proxyMessage.setInfo(new String(infoBytes));
byte[] data = new byte[frameLength - TYPE_SIZE - SERIAL_NUMBER_SIZE - INFO_LENGTH_SIZE - infoLength];
- in.readBytes(data);
+ buf.readBytes(data);
proxyMessage.setData(data);
- in.release();
+ buf.release();
return proxyMessage;
}
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
index 447d2432..c4eb67e3 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
@@ -23,8 +23,12 @@
package org.dromara.neutrinoproxy.core;
import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
+import io.netty.util.Attribute;
+import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
+
import static org.dromara.neutrinoproxy.core.Constants.*;
/**
@@ -40,6 +44,7 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
@Override
protected void encode(ChannelHandlerContext ctx, ProxyMessage msg, ByteBuf out) throws Exception {
+
int bodyLength = TYPE_SIZE + SERIAL_NUMBER_SIZE + INFO_LENGTH_SIZE;
byte[] infoBytes = null;
if (msg.getInfo() != null) {
@@ -51,21 +56,34 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
bodyLength += msg.getData().length;
}
- // write the total packet length but without length field's length.
- out.writeInt(bodyLength);
+ ByteBuf buf = Unpooled.buffer(bodyLength);
- out.writeByte(msg.getType());
- out.writeLong(msg.getSerialNumber());
+ // write the total packet length but without length field's length.
+ buf.writeInt(bodyLength);
+
+ buf.writeByte(msg.getType());
+ buf.writeLong(msg.getSerialNumber());
if (infoBytes != null) {
- out.writeInt(infoBytes.length);
- out.writeBytes(infoBytes);
+ buf.writeInt(infoBytes.length);
+ buf.writeBytes(infoBytes);
} else {
- out.writeInt(0x00);
+ buf.writeInt(0x00);
}
if (msg.getData() != null) {
- out.writeBytes(msg.getData());
+ buf.writeBytes(msg.getData());
}
+
+ // 执行加密
+ byte[] data = new byte[bodyLength];
+ buf.readBytes(data);
+ // 获取加密密钥
+ Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
+ byte[] secureKey = secureKeyAttr.get();
+ // 执行加密
+ byte[] encryptedData = SmEncryptUtil.encryptBySm4(secureKey, data);
+ out.writeByte(encryptedData.length);
+ out.writeBytes(encryptedData);
}
}
From 8842ae2899905b6b82dc60df988dcbe6e9356db0 Mon Sep 17 00:00:00 2001
From: az
Date: Tue, 7 Nov 2023 22:33:39 +0800
Subject: [PATCH 4/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9D=9E=E5=AE=89?=
=?UTF-8?q?=E5=85=A8=E5=88=A4=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../handler/ProxyMessageAuthHandler.java | 4 ++
.../handler/ProxyMessageSecureKeyHandler.java | 3 ++
.../dromara/neutrinoproxy/core/Constants.java | 3 ++
.../core/ProxyMessageDecoder.java | 42 ++++++++++++-------
.../core/ProxyMessageEncoder.java | 36 +++++++++++-----
.../handler/ProxyMessageAuthHandler.java | 4 ++
.../handler/ProxyMessageSecureKeyHandler.java | 4 ++
7 files changed, 69 insertions(+), 27 deletions(-)
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
index 672576aa..233d23d3 100644
--- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java
@@ -45,6 +45,10 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
context.channel().close();
}
+ // 默认设置为非安全链路,需要服务端确认后,再设置为安全链路
+ Attribute booleanAttribute = context.attr(Constants.IS_SECURITY);
+ booleanAttribute.set(false);
+
// 获取认证成功的后的公钥信息,并生成随机密码,加密发到服务端确认
String publicKey = load.get("publicKey").getString();
byte[] secureKey = SmEncryptUtil.generateSm4Key();
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
index 09da501c..49989bd5 100644
--- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
@@ -22,6 +22,9 @@ public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, data);
String m = new String(decryptedData);
if ("ok".equals(m)) {
+ // 设置当前链路为安全,之后使用该链路传输的消息均会加密
+ Attribute booleanAttribute = ctx.attr(Constants.IS_SECURITY);
+ booleanAttribute.set(true);
log.info("Encrypted link established successfully");
} else {
ctx.channel().close();
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
index ab831211..6e1751a3 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
@@ -42,6 +42,8 @@ public interface Constants {
AttributeKey SECURE_KEY = AttributeKey.newInstance("secure_key");
+ AttributeKey IS_SECURITY = AttributeKey.newInstance("is_security");
+
AttributeKey LICENSE_ID = AttributeKey.newInstance("license_id");
AttributeKey TARGET_IP = AttributeKey.newInstance("targetIp");
@@ -62,6 +64,7 @@ public interface Constants {
interface ProxyDataTypeName {
String HEARTBEAT = "HEARTBEAT";
String SECURE_KEY = "SECURE_KEY";
+ String IS_SECURITY = "IS_SECURITY";
String AUTH = "AUTH";
String CONNECT = "CONNECT";
String DISCONNECT = "DISCONNECT";
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
index 3fa077d9..3ac525d2 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
@@ -74,24 +74,34 @@ public class ProxyMessageDecoder extends LengthFieldBasedFrameDecoder {
return null;
}
- int packageLength = in.readInt();
- if (in.readableBytes() < packageLength) {
- return null;
+ Attribute booleanAttribute = ctx.attr(Constants.IS_SECURITY);
+ Boolean isSecurity = booleanAttribute.get();
+
+ ByteBuf buf;
+
+ // 考虑isSecurity为null的情况,null的情况也为false
+ if (isSecurity == true) {
+ int packageLength = in.readInt();
+ if (in.readableBytes() < packageLength) {
+ return null;
+ }
+
+ // 获取加密数据
+ byte[] encryptedBytes = new byte[packageLength];
+ in.readBytes(encryptedBytes);
+ in.release();
+
+ // 获取解密密钥
+ Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
+ byte[] secureKey = secureKeyAttr.get();
+ // 解密
+ byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, encryptedBytes);
+
+ buf = Unpooled.wrappedBuffer(decryptedData);
+ } else {
+ buf = in;
}
- // 获取加密数据
- byte[] encryptedBytes = new byte[packageLength];
- in.readBytes(encryptedBytes);
- in.release();
-
- // 获取解密密钥
- Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
- byte[] secureKey = secureKeyAttr.get();
- // 解密
- byte[] decryptedData = SmEncryptUtil.decryptBySm4(secureKey, encryptedBytes);
-
- ByteBuf buf = Unpooled.wrappedBuffer(decryptedData);
-
ProxyMessage proxyMessage = new ProxyMessage();
int frameLength = buf.readInt();
byte type = buf.readByte();
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
index c4eb67e3..a4101121 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
@@ -56,7 +56,17 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
bodyLength += msg.getData().length;
}
- ByteBuf buf = Unpooled.buffer(bodyLength);
+ Attribute booleanAttribute = ctx.attr(Constants.IS_SECURITY);
+ Boolean isSecurity = booleanAttribute.get();
+
+ ByteBuf buf;
+
+ // 考虑isSecurity为null的情况,null的情况也为false
+ if (isSecurity == true) {
+ buf = Unpooled.buffer(bodyLength);
+ } else {
+ buf = out;
+ }
// write the total packet length but without length field's length.
buf.writeInt(bodyLength);
@@ -75,15 +85,19 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
buf.writeBytes(msg.getData());
}
- // 执行加密
- byte[] data = new byte[bodyLength];
- buf.readBytes(data);
- // 获取加密密钥
- Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
- byte[] secureKey = secureKeyAttr.get();
- // 执行加密
- byte[] encryptedData = SmEncryptUtil.encryptBySm4(secureKey, data);
- out.writeByte(encryptedData.length);
- out.writeBytes(encryptedData);
+ // 考虑isSecurity为null的情况,null的情况也为false
+ if (isSecurity == true) {
+ // 执行加密
+ byte[] data = new byte[bodyLength];
+ buf.readBytes(data);
+ // 获取加密密钥
+ Attribute secureKeyAttr = ctx.attr(SECURE_KEY);
+ byte[] secureKey = secureKeyAttr.get();
+ // 执行加密
+ byte[] encryptedData = SmEncryptUtil.encryptBySm4(secureKey, data);
+ out.writeByte(encryptedData.length);
+ out.writeBytes(encryptedData);
+ }
+
}
}
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
index bc33dedd..8ea5f334 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
@@ -166,6 +166,10 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
}
}
+ // 存储状态为非安全,如果客户端响应以下的公钥信息,则在响应中设置为安全
+ Attribute booleanAttribute = ctx.attr(Constants.IS_SECURITY);
+ booleanAttribute.set(false);
+
// 生成获取SM2密钥对,私钥存入ctx,公钥拼装参数随Auth数据包返回
KeyPairRecord record = SmEncryptUtil.generateSm2KeyPair();
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
index 587d548a..c6970675 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
@@ -56,6 +56,10 @@ public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
// 发送回去,以示确认
ctx.writeAndFlush(ProxyMessage.buildSecureKeyReturnMessage(encryptedSuccessInfoData));
ctx.flush();
+
+ // 设置链路状态为安全,之后使用该链路传输的均会加密
+ Attribute booleanAttribute = ctx.attr(Constants.IS_SECURITY);
+ booleanAttribute.set(true);
}
@Override
From 1698e944ee90705cd3c0c3884d967070d51a2413 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Wed, 8 Nov 2023 09:31:39 +0800
Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BF=90=E8=A1=8C?=
=?UTF-8?q?=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
neutrino-proxy-admin/config/prod.env.js | 2 +-
neutrino-proxy-admin/package.json | 2 +-
neutrino-proxy-client/src/main/resources/app.yml | 6 +++---
neutrino-proxy-server/src/main/resources/app.yml | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/neutrino-proxy-admin/config/prod.env.js b/neutrino-proxy-admin/config/prod.env.js
index 0c43ea73..c388e184 100644
--- a/neutrino-proxy-admin/config/prod.env.js
+++ b/neutrino-proxy-admin/config/prod.env.js
@@ -1,5 +1,5 @@
module.exports = {
NODE_ENV: '"production"',
ENV_CONFIG: '"prod"',
- BASE_API: '"https://api-prod"'
+ BASE_API: '""'
}
diff --git a/neutrino-proxy-admin/package.json b/neutrino-proxy-admin/package.json
index 943c7d6b..9073308a 100644
--- a/neutrino-proxy-admin/package.json
+++ b/neutrino-proxy-admin/package.json
@@ -70,7 +70,7 @@
"friendly-errors-webpack-plugin": "1.6.1",
"html-webpack-plugin": "2.30.1",
"node-notifier": "5.1.2",
- "node-sass": "^4.7.2",
+ "node-sass": "^9.0.0",
"optimize-css-assets-webpack-plugin": "3.2.0",
"ora": "1.3.0",
"portfinder": "1.0.13",
diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml
index c513862e..2645e37a 100644
--- a/neutrino-proxy-client/src/main/resources/app.yml
+++ b/neutrino-proxy-client/src/main/resources/app.yml
@@ -23,7 +23,7 @@ neutrino:
proxy:
protocol:
- max-frame-length: 2097152
+ max-frame-length: 104857600
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
@@ -40,11 +40,11 @@ neutrino:
# 服务端IP
server-ip: ${SERVER_IP:localhost}
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
- server-port: ${SERVER_PORT:9002}
+ server-port: ${SERVER_PORT:9000}
# 是否启用SSL(注意:该配置必须和server-port对应上)
ssl-enable: ${SSL_ENABLE:true}
# 客户端连接唯一凭证
- license-key: ${LICENSE_KEY:}
+ license-key: ${LICENSE_KEY:b0a907332b474b25897c4dcb31fc7eb6}
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
client-id: ${CLIENT_ID:}
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml
index 665cfc83..7e8d4fa1 100644
--- a/neutrino-proxy-server/src/main/resources/app.yml
+++ b/neutrino-proxy-server/src/main/resources/app.yml
@@ -24,7 +24,7 @@ solon.logging.logger:
neutrino:
proxy:
protocol:
- max-frame-length: ${MAX_FRAME_LENGTH:2097152}
+ max-frame-length: ${MAX_FRAME_LENGTH:1048576000}
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
From 55f85861cfe7335ce1b68327a7e57043b7460610 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Wed, 8 Nov 2023 14:08:42 +0800
Subject: [PATCH 6/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=BE=93=E5=87=BA?=
=?UTF-8?q?=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../client/handler/ProxyMessageSecureKeyHandler.java | 1 +
neutrino-proxy-client/src/main/resources/app.yml | 4 ++--
.../java/org/dromara/neutrinoproxy/core/Constants.java | 1 -
.../dromara/neutrinoproxy/core/ProxyMessageDecoder.java | 6 +++++-
.../dromara/neutrinoproxy/core/ProxyMessageEncoder.java | 8 ++++++--
.../server/proxy/handler/ProxyMessageAuthHandler.java | 8 +++++---
.../proxy/handler/ProxyMessageSecureKeyHandler.java | 2 ++
7 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
index 49989bd5..67080776 100644
--- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
+++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageSecureKeyHandler.java
@@ -16,6 +16,7 @@ import org.noear.solon.annotation.Component;
public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
+ log.info("收到服务端的加密确认");
Attribute secureKeyAttr = ctx.attr(Constants.SECURE_KEY);
byte[] secureKey = secureKeyAttr.get();
byte[] data = proxyMessage.getData();
diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml
index 2645e37a..5e88d758 100644
--- a/neutrino-proxy-client/src/main/resources/app.yml
+++ b/neutrino-proxy-client/src/main/resources/app.yml
@@ -23,7 +23,7 @@ neutrino:
proxy:
protocol:
- max-frame-length: 104857600
+ max-frame-length: 1048576000
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
@@ -42,7 +42,7 @@ neutrino:
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
server-port: ${SERVER_PORT:9000}
# 是否启用SSL(注意:该配置必须和server-port对应上)
- ssl-enable: ${SSL_ENABLE:true}
+ ssl-enable: ${SSL_ENABLE:false}
# 客户端连接唯一凭证
license-key: ${LICENSE_KEY:b0a907332b474b25897c4dcb31fc7eb6}
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
index 6e1751a3..574bc5bc 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java
@@ -64,7 +64,6 @@ public interface Constants {
interface ProxyDataTypeName {
String HEARTBEAT = "HEARTBEAT";
String SECURE_KEY = "SECURE_KEY";
- String IS_SECURITY = "IS_SECURITY";
String AUTH = "AUTH";
String CONNECT = "CONNECT";
String DISCONNECT = "DISCONNECT";
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
index 3ac525d2..2e8f8ccf 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageDecoder.java
@@ -27,10 +27,12 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.Attribute;
+import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
import static org.dromara.neutrinoproxy.core.Constants.*;
+@Slf4j
/**
*
* @author: aoshiguchen
@@ -80,7 +82,8 @@ public class ProxyMessageDecoder extends LengthFieldBasedFrameDecoder {
ByteBuf buf;
// 考虑isSecurity为null的情况,null的情况也为false
- if (isSecurity == true) {
+ if (isSecurity != null && isSecurity) {
+ log.info("执行解密逻辑");
int packageLength = in.readInt();
if (in.readableBytes() < packageLength) {
return null;
@@ -100,6 +103,7 @@ public class ProxyMessageDecoder extends LengthFieldBasedFrameDecoder {
buf = Unpooled.wrappedBuffer(decryptedData);
} else {
buf = in;
+ log.info("链路不加密解码");
}
ProxyMessage proxyMessage = new ProxyMessage();
diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
index a4101121..3f1db357 100644
--- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
+++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessageEncoder.java
@@ -27,6 +27,7 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.Attribute;
+import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.core.util.SmEncryptUtil;
import static org.dromara.neutrinoproxy.core.Constants.*;
@@ -36,6 +37,7 @@ import static org.dromara.neutrinoproxy.core.Constants.*;
* @author: aoshiguchen
* @date: 2022/6/16
*/
+@Slf4j
public class ProxyMessageEncoder extends MessageToByteEncoder {
public ProxyMessageEncoder() {
@@ -62,9 +64,11 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
ByteBuf buf;
// 考虑isSecurity为null的情况,null的情况也为false
- if (isSecurity == true) {
+ if (isSecurity != null && isSecurity) {
+ log.info("执行加密逻辑");
buf = Unpooled.buffer(bodyLength);
} else {
+ log.info("不执行加密的链路编码");
buf = out;
}
@@ -86,7 +90,7 @@ public class ProxyMessageEncoder extends MessageToByteEncoder {
}
// 考虑isSecurity为null的情况,null的情况也为false
- if (isSecurity == true) {
+ if (isSecurity != null && isSecurity) {
// 执行加密
byte[] data = new byte[bodyLength];
buf.readBytes(data);
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
index 8ea5f334..5ba72341 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java
@@ -77,6 +77,8 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
+ log.info("收到客户端的认证连接信息");
+
String ip = ((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
Date now = new Date();
@@ -105,7 +107,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
}
LicenseDO licenseDO = licenseService.findByKey(licenseKey);
if (null == licenseDO) {
- log.warn("[client connection] license notfound info:{} ", info);
+ log.warn("[client connection] license not found info:{} ", info);
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey, null));
ctx.channel().close();
clientConnectRecordService.add(new ClientConnectRecordDO()
@@ -113,7 +115,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
.setType(ClientConnectTypeEnum.CONNECT.getType())
.setMsg(licenseKey)
.setCode(SuccessCodeEnum.FAIL.getCode())
- .setErr("license notfound!")
+ .setErr("license not found!")
.setCreateTime(now)
);
return;
@@ -175,7 +177,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
// 私钥存入ctx
Attribute attr = ctx.attr(Constants.SECURE_PRIVATE_KEY);
- attr.setIfAbsent(record.privateKey());
+ attr.set(record.privateKey());
// 发送认证成功消息
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "auth success!", licenseKey, record.publicKey()));
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
index c6970675..9ace39a5 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageSecureKeyHandler.java
@@ -21,6 +21,8 @@ public class ProxyMessageSecureKeyHandler implements ProxyMessageHandler {
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
+ log.info("收到客户端的加密信息");
+
// data为加密后的密码,info为加密密码的摘要
byte[] data = proxyMessage.getData();
String receivedDigest = proxyMessage.getInfo();