Files
min-vpn-non-core/src/main/java/TCPNet/SSL.java
T

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;
}
}
}