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();