diff --git a/app/build.gradle b/app/build.gradle index 31ce05a..699a4eb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,7 +34,7 @@ android { } compileSdkVersion 30 - buildToolsVersion "30.0.3" + buildToolsVersion '30.0.3' sourceSets.main.jniLibs.srcDirs = ['libs'] @@ -75,8 +75,17 @@ android { } dependencies { - implementation files('libs\\gmhelper.jar') - implementation files('libs\\BaiduLBS_Android.jar') + implementation files('libs/gmhelper.jar') + implementation files('libs/BaiduLBS_Android.jar') + implementation files('libs/vpnjce-1.0.jar') + + // 在依赖中添加对jre的依赖,以尝试解决android.jar中原生javax与java中的javax的冲突问题 + //noinspection GradlePath +// implementation files('C:/MyEnv/Java/jdk1.8.0_301/jre/lib/rt.jar') +// compileOnly files('C:/MyEnv/Java/jdk1.8.0_301/jre/lib/rt.jar') +// implementation files('C:/MyEnv/Java/jdk1.8.0_301/jre/lib/jce.jar') +// compileOnly files('C:/MyEnv/Java/jdk1.8.0_301/jre/lib/jce.jar') +// implementation files('libs\\jce.jar') // testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' diff --git a/app/libs/vpnjce-1.0.jar b/app/libs/vpnjce-1.0.jar new file mode 100644 index 0000000..7fd84c8 Binary files /dev/null and b/app/libs/vpnjce-1.0.jar differ diff --git a/app/src/main/java/com/pkusz/min_vpn_client/services/MINVpnConnection.java b/app/src/main/java/com/pkusz/min_vpn_client/services/MINVpnConnection.java index 962bc87..29e4e1a 100644 --- a/app/src/main/java/com/pkusz/min_vpn_client/services/MINVpnConnection.java +++ b/app/src/main/java/com/pkusz/min_vpn_client/services/MINVpnConnection.java @@ -18,14 +18,12 @@ import android.text.TextUtils; import androidx.annotation.RequiresApi; import com.pkusz.min_vpn_client.model.MINVpnSettingAPI; -import com.pkusz.min_vpn_client.utils.AESHelperForConnection; import com.pkusz.min_vpn_client.utils.IPPackageUtil; import com.pkusz.min_vpn_client.utils.KeyManager; -import com.pkusz.min_vpn_client.utils.RSACryptoForConnection; import com.pkusz.min_vpn_client.utils.RuleUtil; import com.pkusz.min_vpn_client.utils.SM2HelperForConnection; +import com.pkusz.min_vpn_client.utils.SM3HelperForConnection; import com.pkusz.min_vpn_client.utils.SM4HelperForConnection; -import com.pkusz.min_vpn_client.utils.SafetyInfoUtil; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -43,8 +41,6 @@ import logicface.LogicFace; import logicface.LogicFaceException; import mgmt.RegisterPrefixHelper; import packet.CPacket; -import packet.Data; -import packet.Interest; import packet.PacketException; import util.ByteHelper; @@ -71,6 +67,8 @@ public class MINVpnConnection implements Runnable{ private final byte[] mSharedSecret; private final String mSharedSecretString; private byte[] mEncryptedAESSeed; + // 实际使用的密钥是:随机产生的密钥经过sm3哈希,取前16字节 + private byte[] realSecret; // 代理地址 todo:?? private String mProxyHostName; @@ -80,7 +78,7 @@ public class MINVpnConnection implements Runnable{ private final boolean mAllow; private final Set mPackages; - // todo: ?? + // 服务器给客户端的tun网卡分配的IP地址 private String allocatedAddress; // 待决Intent、回调函数(建立连接成功;建立连接失败;长时间不操作的超时回调) @@ -127,8 +125,11 @@ public class MINVpnConnection implements Runnable{ mServerPort=serverPort; mSharedSecret=sharedSecret; mSharedSecretString=new String(mSharedSecret); -// mEncryptedAESSeed= RSACryptoForConnection.encrypt5(mSharedSecretString); - mEncryptedAESSeed= SM2HelperForConnection.encrypt(mSharedSecretString); + mEncryptedAESSeed= SM2HelperForConnection.encryptWithSM2(mSharedSecretString); + realSecret= SM3HelperForConnection.getSM3Hash16(mSharedSecret); + + // 测试sm4 + SM4HelperForConnection.encryptWithSM4(realSecret, "sss".getBytes()); // 代理地址(?) if(!TextUtils.isEmpty(proxyHostName)) { @@ -218,7 +219,12 @@ public class MINVpnConnection implements Runnable{ byte[] ipPackageData = new byte[readLen]; System.arraycopy(buff1.array(), 0, ipPackageData, 0, readLen); System.out.println("mSharedSecretString length: "+mSharedSecretString.length()); - byte[] encrytedIPPackage = SM4HelperForConnection.encryptWithSM4(mSharedSecretString, ipPackageData); + System.out.println("realSecret length: "+realSecret.length); + byte[] encrytedIPPackage = SM4HelperForConnection.encryptWithSM4(realSecret, ipPackageData); + if(encrytedIPPackage==null){ + System.out.println("sm4加密错误!!!"); + return; + } System.out.println("encryptedIPPackage len: " + encrytedIPPackage.length); System.out.println("buff2 position: " + buff2.position()); buff2.put(encrytedIPPackage); @@ -243,7 +249,12 @@ public class MINVpnConnection implements Runnable{ // face.registerIdentifier(new Identifier(this.localPrefix),5000,helper); // 2. 接收服务器返回的数据包,放入buf2 - CPacket interest = face.receiveCPacket(-1); + CPacket interest; + try { + interest = face.receiveCPacket(0); + }catch (Exception e){ + continue; + } System.out.println("recv interest packet, name : " + interest.getSrcIdentifier().toString()); System.out.println("兴趣包中装的数据长度 : " + interest.payload.getValue().length); int dataLen = interest.payload.getValue().length; @@ -256,7 +267,7 @@ public class MINVpnConnection implements Runnable{ System.arraycopy(buf2.array(), 0, decrpytedIPPackage, 0, buf2.position()); ByteBuffer buf3 = ByteBuffer.allocate(5000); // buf3.put(Objects.requireNonNull(AESHelperForConnection.decryptWithAES(mSharedSecretString, decrpytedIPPackage))); - buf3.put(Objects.requireNonNull(SM4HelperForConnection.decryptWithSM4(mSharedSecretString, decrpytedIPPackage))); + buf3.put(Objects.requireNonNull(SM4HelperForConnection.decryptWithSM4(realSecret, decrpytedIPPackage))); int decryptedDataLen = buf3.position(); byte firstByte = buf3.get(0); if (firstByte == 0) { @@ -270,7 +281,7 @@ public class MINVpnConnection implements Runnable{ System.out.println("transfer data error: outputStream.write error"); } } - } catch (SecurityException | LogicFaceException e) { + } catch (SecurityException e) { e.printStackTrace(); System.out.println("transfer data error: recvFromServerAndReadThread.start error"); } diff --git a/app/src/main/java/com/pkusz/min_vpn_client/utils/IPPackageUtil.java b/app/src/main/java/com/pkusz/min_vpn_client/utils/IPPackageUtil.java index a866bee..bbe3875 100644 --- a/app/src/main/java/com/pkusz/min_vpn_client/utils/IPPackageUtil.java +++ b/app/src/main/java/com/pkusz/min_vpn_client/utils/IPPackageUtil.java @@ -22,4 +22,6 @@ public class IPPackageUtil { return null; } + + } diff --git a/app/src/main/java/com/pkusz/min_vpn_client/utils/SM2HelperForConnection.java b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM2HelperForConnection.java index 5d1b38c..92f4d6e 100644 --- a/app/src/main/java/com/pkusz/min_vpn_client/utils/SM2HelperForConnection.java +++ b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM2HelperForConnection.java @@ -24,7 +24,7 @@ public class SM2HelperForConnection { // return enRes; // } - public static byte[] encrypt(String data){ + public static byte[] encryptWithSM2(String data){ byte[] enRes; try { enRes = BC_KeyManager.sm2encrypt(pubkey_ForNewVPN.getBytes(StandardCharsets.UTF_8), diff --git a/app/src/main/java/com/pkusz/min_vpn_client/utils/SM3HelperForConnection.java b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM3HelperForConnection.java new file mode 100644 index 0000000..9283019 --- /dev/null +++ b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM3HelperForConnection.java @@ -0,0 +1,29 @@ +package com.pkusz.min_vpn_client.utils; +/* + * @Author: Wang Feng + * @Description: + * @Version: 1.0.0 + * @Date: 10:07 2021/7/22 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ + +import org.zz.gmhelper.SM3Util; + +import java.util.Arrays; + +public class SM3HelperForConnection { + /** + * 将传入参数使用sm3做哈希,然后返回前16个字节 + * @param randBytes + * @return + */ + public static byte[] getSM3Hash16(byte[] randBytes){ + System.out.println("sm3哈希之前的密钥:"+new String(randBytes)); + byte[] hashRes=SM3Util.hash(randBytes); + byte[] res=new byte[16]; + System.arraycopy(hashRes,0,res,0,16); + System.out.println("sm3哈希得到的密钥:"+res.length+" , "+new String(res)); + System.out.println("sm3哈希得到的密钥:"+Arrays.toString(res)); + return res; + } +} diff --git a/app/src/main/java/com/pkusz/min_vpn_client/utils/SM4HelperForConnection.java b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM4HelperForConnection.java index fc767db..d672b91 100644 --- a/app/src/main/java/com/pkusz/min_vpn_client/utils/SM4HelperForConnection.java +++ b/app/src/main/java/com/pkusz/min_vpn_client/utils/SM4HelperForConnection.java @@ -9,10 +9,15 @@ package com.pkusz.min_vpn_client.utils; import android.annotation.SuppressLint; +import com.pkusz.min_vpn_client.utils.gmutil.sm4.VPN_SM4; + +import org.zz.gmhelper.SM4Util; + import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.Arrays; import java.util.Random; import javax.crypto.BadPaddingException; @@ -20,6 +25,7 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import VMSConnection.Security.BC_KeyManager; +import VMSConnection.Security.SM4.BC_SM4; public class SM4HelperForConnection { public static byte[] encryptWithSM4(String secret,byte[] rawText){ @@ -40,6 +46,38 @@ public class SM4HelperForConnection { } } + public static byte[] encryptWithSM4(byte[] secretkey, byte[] origData) { +// try { +// return VPN_SM4.encrypt_ECB_Padding(secretkey, origData); +// } catch (Exception e){ +// e.printStackTrace(); +// return null; +// } + try { + return SM4Util.encrypt_ECB_Padding(secretkey,origData); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) { + e.printStackTrace(); + return null; + } + } + + public static byte[] decryptWithSM4(byte[] secretkey, byte[] crypted){ +// System.out.println("sec: " + secretkey); +// System.out.println("cry: " + Arrays.toString(crypted)); +// try { +// return VPN_SM4.decrypt_ECB_Padding(secretkey, crypted); +// } catch (Exception e){ +// e.printStackTrace(); +// return null; +// } + try { + return SM4Util.decrypt_ECB_Padding(secretkey,crypted); + } catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException e) { + e.printStackTrace(); + return null; + } + } + /** * 获取长度为16字节的随机种子/随机密钥 * @return diff --git a/app/src/main/java/com/pkusz/min_vpn_client/utils/gmutil/sm4/VPN_SM4.java b/app/src/main/java/com/pkusz/min_vpn_client/utils/gmutil/sm4/VPN_SM4.java new file mode 100644 index 0000000..dd4c69c --- /dev/null +++ b/app/src/main/java/com/pkusz/min_vpn_client/utils/gmutil/sm4/VPN_SM4.java @@ -0,0 +1,140 @@ +package com.pkusz.min_vpn_client.utils.gmutil.sm4; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.vpncrypto.*; +import javax.vpncrypto.spec.IvParameterSpec; +import javax.vpncrypto.spec.SecretKeySpec; +import java.security.*; + +/* + * @Author: hongyu guo + * @Description: sm4算法 + * 解尝试解决报错:Provider BC does not provide SM4/ECB/PKCS5Padding + * + * @Version: 1.0.0 + * @Date: 16:26 2021/03/04 + * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 + */ +public class VPN_SM4 { + static { + Security.addProvider(new BouncyCastleProvider()); + } + public static final String ALGORITHM_NAME = "SM4"; + public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding"; + public static final String ALGORITHM_NAME_ECB_NOPADDING = "SM4/ECB/NoPadding"; + public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding"; + public static final String ALGORITHM_NAME_CBC_NOPADDING = "SM4/CBC/NoPadding"; + + /** + * SM4算法目前只支持128位(即密钥16字节) + */ + public static final int DEFAULT_KEY_SIZE = 128; + + /** + * 生成16字节的sm4 key + * @param + * @return byte[] + * @throws NoSuchAlgorithmException + * @author hongyu guo + * @date 2021/3/15 + **/ + public static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException { + return generateKey(DEFAULT_KEY_SIZE); + } + + public static byte[] generateKey(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException { + KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); + kg.init(keySize, new SecureRandom()); + return kg.generateKey().getEncoded(); + } + + public static byte[] encrypt_ECB_Padding(byte[] key, byte[] data) + throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, + NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(data); + } + + public static byte[] decrypt_ECB_Padding(byte[] key, byte[] cipherText) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { + Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key); + return cipher.doFinal(cipherText); + } + + public static byte[] encrypt_ECB_NoPadding(byte[] key, byte[] data) + throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, + NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_NOPADDING, Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(data); + } + + public static byte[] decrypt_ECB_NoPadding(byte[] key, byte[] cipherText) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { + Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_NOPADDING, Cipher.DECRYPT_MODE, key); + return cipher.doFinal(cipherText); + } + + public static byte[] encrypt_CBC_Padding(byte[] key, byte[] iv, byte[] data) + throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, + NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, + InvalidAlgorithmParameterException { + Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv); + return cipher.doFinal(data); + } + + public static byte[] decrypt_CBC_Padding(byte[] key, byte[] iv, byte[] cipherText) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, + InvalidAlgorithmParameterException { + Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv); + return cipher.doFinal(cipherText); + } + + public static byte[] encrypt_CBC_NoPadding(byte[] key, byte[] iv, byte[] data) + throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, + NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, + InvalidAlgorithmParameterException { + Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv); + return cipher.doFinal(data); + } + + public static byte[] decrypt_CBC_NoPadding(byte[] key, byte[] iv, byte[] cipherText) + throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, + InvalidAlgorithmParameterException { + Cipher cipher = generateCBCCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv); + return cipher.doFinal(cipherText); + } + + private static Cipher generateECBCipher(String algorithmName, int mode, byte[] key) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, + InvalidKeyException { + Cipher cipher = null; + try { + cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); + } catch (Exception e) { + e.printStackTrace(); + } + Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); + cipher.init(mode, sm4Key); + return cipher; + } + + private static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv) + throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, + NoSuchProviderException, NoSuchPaddingException { + Cipher cipher = null; + try { + cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); + } catch (Exception e) { + e.printStackTrace(); + } + Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + cipher.init(mode, sm4Key, ivParameterSpec); + return cipher; + } +}