vpn客户端实现 远程全职
一般月薪8000元- 项目类型:其他
- 每月工作: 10天
- 工作方式:定期坐班
职位详情
【需求】
实现iOS上的vpn建连,简单的界面展示,功能封装成为lib
和vpn中间服务器建连,实现iOS全局VPN。
连接过程简述:
iOS上读取公钥加密一个36字节的指纹(Android实现使用MAC,IMSI,IMEI产生),经过AES加密UDP发给vpn服务器,然后等待读取返回的vpn参数,设置vpn连接。
【Android端参考程序】
//与vpn服务器连接握手程序
private void handshake(DatagramChannel tunnel) throws Exception {
// Allocate the buffer for handshaking.
ByteBuffer packet = ByteBuffer.allocate(1032);
byte[] prepareBuf = new byte[68];
InputStream isPub = getResources().openRawResource(R.raw.xpublic);
//InputStream isPemPub = getResources().openRawResource(R.raw.pempublic);
getDeviceInfo();
ByteBuffer certHeader = ByteBuffer.allocate(144);
// Send the secret several times in case of packet loss.
byte[] ID = new byte[36],LogonData = new byte[144];
String PubKey = mToolSet.readKey(isPub);
mToolSet.absorbByteArray(ID,0,mWifiMac);
mToolSet.absorbByteArray(ID,6,mIMSI);
mToolSet.absorbByteArray(ID,21,mIMEI);
//android java实现
if(useJava) {
if (mToolSet.vpnLogonData(ID,PubKey,LogonData)){
certHeader.put(LogonData);
for (int i = 0; i < 3; ++i) {
certHeader.position(0);
tunnel.write(certHeader);
}
}
} else {
//C lib实现
//String PemPubKey = mToolSet.readKey(isPemPub);
//VpnJni.vpnLogonData(ID,PemPubKey,LogonData);
}
// Wait for the parameters within a limited time.
for (int i = 0; i < 50; ++i) {
Thread.sleep(100);
// Normally we should not receive random packets.
int length = tunnel.read(packet);
if (length > 0 ) {
byte[] InData = new byte[length];
packet.flip();
packet.get(InData);
byte[] ParamData = new byte[InData.length];
int Ret = mToolSet.vpnInputData(InData,ParamData);
if(1 == Ret)
configure(new String(ParamData).trim());
else continue;
return;
}
}
Log.e(TAG,"error throw time out exception");
throw new IllegalStateException("Timed out");
}
//AES解码vpn服务器返回的链接参数
public boolean vpnLogonData(byte[] ID,String PubKey,byte[] LogonData)
{
mAesKey = new byte[AES_KEY_SIZE];
mAesIv = new byte[AES_KEY_SIZE];
byte[] prepareBuf = new byte[68];
mAesKey = GenerateRandom(AES_KEY_SIZE);
mAesIv = GenerateRandom(AES_KEY_SIZE);
absorbByteArray(prepareBuf,0,mAesKey);
absorbByteArray(prepareBuf,16,mAesIv);
absorbByteArray(prepareBuf,32,ID);
PublicKey pubKey=null;
try{
pubKey = loadPublicKey(PubKey);
} catch (Exception e){
e.printStackTrace();
}
byte[] encryptedArray = encryptData(prepareBuf, pubKey);
ByteBuffer certHeader = ByteBuffer.allocate(144);
certHeader.putInt(0x20070811);
certHeader.putInt(encryptedArray.length);
certHeader.put(encryptedArray);
certHeader.putInt((int) 0);
int CRCheck = GetCrc32(encryptedArray);
certHeader.putInt((int)CRCheck);
certHeader.position(0);
certHeader.get(LogonData, 0, LogonData.length);
return true;
}
public int vpnInputData(byte[] Encrypted,byte[] Blank) throws Exception
{
int CRCheck =0;
byte[] MagicNumber = copyOfRange(Encrypted,0,4);
byte[] TailCheckSum = copyOfRange(Encrypted,Encrypted.length-4,Encrypted.length);
byte[] Param = copyOfRange(Encrypted,4,Encrypted.length - 4);
byte[] newAesIv = mAesIv.clone();
byte[] newPacket = null;
try {
newPacket = AesDecodeBuf(mAesKey,newAesIv,Param);
} catch(Exception e){
e.printStackTrace();
}
CRCheck = GetCrc32(Param);
int CalcChecksum = byteArrayToInt(TailCheckSum);
if(CRCheck != CalcChecksum){
throw new Exception("bad checksum");
}
absorbByteArray(Blank,0,newPacket);
int MagicInt = byteArrayToInt(MagicNumber);
if(0x19750118 == MagicInt){
return 1;
} else if(0x19770718 == MagicInt){
return 2;
}
return 3;
}