mirror of
https://gitee.com/willfree/min-vpn-non-core.git
synced 2026-10-05 01:15:48 +08:00
238 lines
8.2 KiB
Java
238 lines
8.2 KiB
Java
package TCPNet;
|
|
|
|
import Security.BC_KeyManager;
|
|
import TCPNet.request.BaseRequest;
|
|
import TCPNet.response.BaseResponse;
|
|
import Utils.Base64Helper;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.alibaba.fastjson.parser.JSONToken;
|
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
|
|
|
import javax.crypto.BadPaddingException;
|
|
import javax.crypto.IllegalBlockSizeException;
|
|
import javax.crypto.NoSuchPaddingException;
|
|
import java.lang.reflect.Field;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.security.InvalidKeyException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.NoSuchProviderException;
|
|
import java.util.ArrayList;
|
|
import java.util.Random;
|
|
|
|
/*
|
|
* @Author: Wang Feng
|
|
* @Description:
|
|
* @Version: 1.0.0
|
|
* @Date: 20:50 2021/6/24
|
|
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
|
*/
|
|
class SSL_SetupMessage extends BaseRequest {
|
|
public String Pubkey;
|
|
public String Secretkey;
|
|
}
|
|
class SSL_Message_Helper{
|
|
// 为了直接将SSL_Message的json格式解析为java对象,
|
|
// 而定义本类
|
|
public int IsEncrypted;
|
|
public int MType;
|
|
public String Data;
|
|
public String Pubkey = "";
|
|
public int Code = 0;
|
|
}
|
|
class SSL_Message extends BaseRequest{
|
|
public int IsEncrypted;
|
|
public int MType;
|
|
public byte[] Data;
|
|
public String Pubkey="";
|
|
public int Code=0;
|
|
|
|
@Override
|
|
public void unJson(byte[] data,Object thisObj) {
|
|
SSL_Message_Helper newObj= JSONObject.parseObject(new String(data), SSL_Message_Helper.class);
|
|
try {
|
|
Class thiscls = SSL_Message.class;
|
|
Class cls = SSL_Message_Helper.class;
|
|
Field[] fields = cls.getDeclaredFields();
|
|
for (int i = 0; i < fields.length; i++) {
|
|
Field f = fields[i];
|
|
f.setAccessible(true);
|
|
// 将属性值的名字的属性值的值放入this中
|
|
Field thisf = thiscls.getDeclaredField(f.getName());
|
|
thisf.setAccessible(true);
|
|
if(thisf.getType()==(byte[].class)){
|
|
// byte[]需要解码base64
|
|
String base64S=(String)(f.get(newObj));
|
|
byte[] decodeBytes= Base64Helper.BlockChain_Base64Decode_GoLanUn(base64S);
|
|
thisf.set(this, decodeBytes);
|
|
}else {
|
|
thisf.set(this, f.get(newObj));
|
|
}
|
|
}
|
|
} catch (IllegalAccessException | NoSuchFieldException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
class SSL_RespMessage extends BaseResponse {
|
|
public int Code;
|
|
}
|
|
public class SSL {
|
|
// 是否加密
|
|
public static final int encrypted=0;
|
|
public static final int not_encrypted=1;
|
|
// SSL_Message类型
|
|
public static final int normal=0;
|
|
public static final int setup=1;
|
|
public static final int resp=2;
|
|
// SSL_RespMessage类型
|
|
public static final int success=200;
|
|
public static final int bad_request=400;
|
|
public static final int not_authorized=403;
|
|
public static final int server_error=500;
|
|
|
|
/**
|
|
* 协商对称密钥
|
|
* @param conn
|
|
* @param pubKey 用户公钥
|
|
* @param key 无用参数,内含pubKey
|
|
* @param serverKey 服务器公钥
|
|
* @return 协商成功的对称密钥
|
|
*/
|
|
public static String sslSetup(Conn conn, String pubKey,
|
|
BC_KeyManager key,BC_KeyManager serverKey){
|
|
// 取一个十六位的密钥
|
|
String secretKey=String.format("%016d",
|
|
Math.abs(new Random(System.currentTimeMillis()).nextLong()))
|
|
.substring(0,16);
|
|
// 构造SSL_SetupMessage(公钥&密钥)
|
|
SSL_SetupMessage sm=new SSL_SetupMessage();
|
|
sm.Pubkey=pubKey;
|
|
sm.Secretkey=secretKey;
|
|
String data;
|
|
try {
|
|
data=sm.toJson();
|
|
} catch (IllegalAccessException e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
// 用公钥去加密它
|
|
byte[] encData;
|
|
try {
|
|
encData=serverKey.Encrypt(data);
|
|
} catch (InvalidCipherTextException e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
|
|
// 构造SSL_Message
|
|
SSL_Message sslMessage=new SSL_Message();
|
|
sslMessage.IsEncrypted=encrypted;
|
|
sslMessage.MType=setup;
|
|
sslMessage.Data =encData;
|
|
String ms=null;
|
|
try {
|
|
ms=sslMessage.toJson();
|
|
} catch (IllegalAccessException e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
|
|
System.out.println("test 000: mesdata: "+new String(ms.getBytes(StandardCharsets.UTF_8)));
|
|
|
|
// 将SSL_Message写给服务器(内含:用户公钥、用户对称密钥)
|
|
if(!conn.writeV2(ms.getBytes(StandardCharsets.UTF_8))){
|
|
System.out.println("SSL write error");
|
|
return null;
|
|
}
|
|
|
|
System.out.println("test 111");
|
|
|
|
// 读取服务器应答信息
|
|
byte[] resData=conn.readSSL();
|
|
if(resData==null){
|
|
System.out.println("SSL readSSL error");
|
|
return null;
|
|
}
|
|
|
|
System.out.println("test 222: "+new String(resData));
|
|
System.out.println("secretkey: "+secretKey);
|
|
// 用对称密钥解密应答信息
|
|
byte[] decRes;
|
|
try {
|
|
// todo:这里sm4有问题
|
|
// decRes="{\"Code\":200}".getBytes(StandardCharsets.UTF_8);
|
|
decRes=BC_KeyManager.SM4Decrypt(secretKey,resData);
|
|
} catch (IllegalBlockSizeException | InvalidKeyException | NoSuchProviderException
|
|
| NoSuchAlgorithmException | BadPaddingException | NoSuchPaddingException e) {
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
|
|
// 将解密信息转为Java对象
|
|
SSL_RespMessage resp=new SSL_RespMessage();
|
|
resp.unJson(decRes,resp);
|
|
|
|
// 判断应答信息的code
|
|
if(resp.Code!=success){
|
|
System.out.println("SSL setup failed, the server doesn't accept the request, " +
|
|
"and the status code is "+resp.Code);
|
|
return null;
|
|
}
|
|
|
|
return secretKey;
|
|
}
|
|
|
|
/**
|
|
* 使用密钥解密数据
|
|
* @param data
|
|
* @param role
|
|
* @param secretKey
|
|
* @return 泛型数组,依次存储:string(对称密钥) int(是否加密) int(code) byte[](解密数据)
|
|
*/
|
|
public static ArrayList sslDePacket(byte[] data, int role, String secretKey){
|
|
ArrayList result=new ArrayList();
|
|
result.add("");
|
|
result.add(not_encrypted);
|
|
result.add(400);
|
|
result.add(null);
|
|
// json转java对象
|
|
SSL_Message res=new SSL_Message();
|
|
res.unJson(data,res);
|
|
// 没有加密直接返回 200 和源数据res.Data
|
|
if(res.IsEncrypted==not_encrypted){
|
|
return result;
|
|
}else if(res.IsEncrypted==encrypted) {
|
|
// 加密 判断role
|
|
if(role==0){
|
|
// todo:根据解析出来的数据中的公钥ID从本地MAP获取公钥 对数据SM4解密
|
|
// todo: 这里是server应该事先的处理逻辑
|
|
System.out.println("sslDePacket error: role==0");
|
|
return result;
|
|
}else{
|
|
// 直接使用传入的密钥 对数据SM4解密
|
|
if(secretKey.equals("")){
|
|
System.out.println("sslDePacket error: secretKey == \"\"");
|
|
return result;
|
|
}
|
|
byte[] ans;
|
|
try {
|
|
ans= BC_KeyManager.SM4Decrypt(secretKey,res.Data);
|
|
} catch (IllegalBlockSizeException | NoSuchProviderException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | NoSuchPaddingException e) {
|
|
e.printStackTrace();
|
|
return result;
|
|
}
|
|
if(ans==null){
|
|
System.out.println("SSL depacket failed, the secretKey can't use to decrypt the data");
|
|
return result;
|
|
}
|
|
result.set(1,encrypted);
|
|
result.set(2,200);
|
|
result.set(3,ans);
|
|
return result;
|
|
}
|
|
}else{
|
|
return result;
|
|
}
|
|
}
|
|
}
|