應該堅決拒絕 不加密地明文傳輸敏感數據 這對整個安卓生態都是不負責的!
最危險的是直接使用HTTP協議登錄賬戶或交換數據。例如,攻擊者在自己設置的釣魚網絡中配置DNS服務器,將軟件要連接的服務器域名解析至攻擊者的另一臺服務器在,這臺服務器就可以獲得用戶登錄信息,或者充當客戶端與原服務器的中間人,轉發雙方數據。
這類問題的解決方法很顯然-----對敏感數據採用基於SSL/TLS的HTTPS進行傳輸。
Android使用https
HTTPS和HTTP的區別主要如下:
- https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
- http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
- http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
安卓裏使用https的步驟如下,創建一個HttpsURLConnection並設置屬性,然後去效驗本地證書,接着發起請求,接受結果。
1.創建一個HttpsURLConnection並設置屬性
URL url = new URL("https://baidu.com");
HttpsURLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setConnectTimeout(Common.TIME_OUT);
urlConnection.setReadTimeout(Common.FILE_TIME_OUT);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
urlConnection.setRequestProperty("Accept-Encoding", "gzip");
2.效驗本地證書有兩種方式,一種是不安全的,什麼證書都相信,另一種則是隻相信指定的證書,對其進行效驗。
效驗要通過SSLSocketFactory創建的 SSLSocket來進行,默認的 SSLSocketFactory校驗服務器的證書時,會信任設備內置的100多個根證書。
private synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
return defaultSslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError();
}
}
校驗服務器的證書,其實就是通過TrustManager來操作的,更一般的說是X509TrustManager;
private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}, null);
return sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError();
}
}
這種效驗過程什麼證書都會信任,沒有安全性可言,接下來我們看正確的配置
public static SSLContext getSSLContext() {
// 從assets中加載證書,取到證書的輸入流
InputStream is = getApplicationContext().getAssets().open("srca.cer");
// 證書工廠
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(is);
// 加載證書到密鑰庫中
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null);
keyStore.setCertificateEntry("cert", ca);
// 加載密鑰庫到信任管理器
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
// 用 TrustManager 初始化一個 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
urlCon.setSSLSocketFactory(sslContext.getSocketFactory());
}
Android P 限制了明文流量的網絡請求,非加密的流量請求都會被系統禁止掉,如果當前應用的請求是http請求,而非 https,這樣就會導系統禁止當前應用進行該請求,如果WebView 的url用http協議,同樣會出現加載失敗,https則不受影響。
所以需要做一個簡單的配置,在manifest的application標籤下增加一行配置,同時增加一個xml文件。
android:networkSecurityConfig="@xml/network_security_config"
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" overridePins="true"/>
<certificates src="user" overridePins="true" />
</trust-anchors>
</base-config>
</network-security-config>
然後傳遞參數並獲取結果
Iterator<Entry<String, Object>> it = params.entrySet().iterator();
while (it.hasNext()) {
Entry<String, Object> element = (Entry<String, Object>) it.next();
sb2.append(element.getKey());
sb2.append("=");
sb2.append(element.getValue());
sb2.append("&");
}
if (sb2.length() > 0) {
sb2.deleteCharAt(sb2.length() - 1);
}
os = urlCon.getOutputStream();
os.write(sb2.toString().getBytes());
os.flush();
int statusCode = urlCon.getResponseCode();
if (statusCode == HttpsURLConnection.HTTP_OK) {
is = urlCon.getInputStream();
String contentEncoding = urlCon.getContentEncoding();
if ((contentEncoding != null) && contentEncoding.contains("gzip")) {
is = new GZIPInputStream(new BufferedInputStream(is));
}
// 創建字節輸出流對象
baos = new ByteArrayOutputStream();
// 定義讀取的長度
int len = 0;
// 定義緩衝區
byte[] buffer = new byte[1024];
// 按照緩衝區的大小,循環讀取
while ((len = is.read(buffer)) != -1) {
// 根據讀取的長度寫入到os對象中
baos.write(buffer, 0, len);
}
// 返回字符串
String result = new String(baos.toByteArray(), "utf-8");
}
https比較消耗流量,所以可以採用http配合高強度加密的方式來進行網絡傳輸
Android中使用 加解密方式
常見的加解密方式:
Base64加密, 單向加密(MD5和SHA), 對稱加密(DES和AES), 非對稱加密(RSA), 非數字簽名等。
- Base64算法
Base64是一種基於64個基本字符,加密後的內容只包含這64個字符,加密後長度會變大。它是最簡單的一種算法,一般用於加密URL,還有在進行對稱和非對稱加解密前也會進行一下Base64轉換,保證沒有特殊字符,從而進行網絡傳輸。
// 需要引入包:java.util.Base64
// Base64加密
private static String encode(String str) {
byte[] encodeBytes = Base64.getEncoder().encode(str.getBytes());
return new String(encodeBytes);
}
// Base64解密
private static String decode(String str) {
byte[] decodeBytes = Base64.getDecoder().decode(str.getBytes());
return new String(decodeBytes);
}
- MD5
計算字符串MD5值
@NonNull
public static String md5(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result.append(temp);
}
return result.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
計算文件的MD5值
@NonNull
public static String md5(File file) {
if (file == null || !file.isFile() || !file.exists()) {
return "";
}
FileInputStream in = null;
String result = "";
byte buffer[] = new byte[8192];
int len;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer)) != -1) {
md5.update(buffer, 0, len);
}
byte[] bytes = md5.digest();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result += temp;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
MD5加密安全性
雖然MD5加密本身是不可逆的,但並不是不可破譯的,常見破解機制爲窮舉法,即 跑字典,一些常見的密碼很容易在大型數據庫中匹配到相同的MD5值,所以我們要想辦法增加加密安全性。
1、對字符串多次MD5加密
@NonNull
public static String md5(String string, int times) {
if (TextUtils.isEmpty(string)) {
return "";
}
String md5 = md5(string);
for (int i = 0; i < times - 1; i++) {
md5 = md5(md5);
}
return md5(md5);
}
2、MD5加鹽
加鹽就是使用一個額外的鹽值與原字符串一起加密,通常鹽值可以使用用戶名、string明文的hascode或是隨機生成的字符串。
@NonNull
public static String md5(String string, String slat) {
if (TextUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest((string + slat).getBytes());
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result.append(temp);
}
return result.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
- 對稱加密算法
對稱加密是指加解密使用同一個祕鑰,這需要雙方事前都知道該祕鑰。主要分爲DES和AES,一般會在加解密前進行Base64轉換,去除特殊字符,從而進行網絡傳輸。
1.DES:數據標準加密
DES算法經過16論迭代,使用56比特長度密鑰加密64比特長度(分組長度)的明文獲得64比特的密文。
/**
* 數據標準加密
* DES算法經過16論迭代,使用56比特長度密鑰加密64比特長度(分組長度)的明文獲得64比特的密文。
*/
public class DESUtil {
// 初始化向量
private static byte[] iv = { 'a', 'b', 'c', 'd', 'e', 1, 2, '*' };
// DES加密
// encryptText爲原文
// encryptKey爲密匙
private static String encryptDES(String encryptText, String encryptKey)
throws Exception {
// 實例化IvParameterSpec對象,使用指定的初始化向量
IvParameterSpec spec = new IvParameterSpec(iv);
// 實例化SecretKeySpec類,根據字節數組來構造SecretKeySpec
SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(), "DES");
// 創建密碼器
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 用密碼初始化Cipher對象
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
// 執行加密操作
byte[] encryptData = cipher.doFinal(encryptText.getBytes());
// 返回加密後的數據
return Base64.getEncoder().encodeToString(encryptData);
}
// 解密
private static String decryptDES(String decryptString, String decryptKey)
throws Exception {
// 先使用Base64解密
byte[] base64byte = Base64.getDecoder().decode(decryptString);
// 實例化IvParameterSpec對象,使用指定的初始化向量
IvParameterSpec spec = new IvParameterSpec(iv);
// 實例化SecretKeySpec類,根據字節數組來構造SecretKeySpec
SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(), "DES");
// 創建密碼器
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 用密碼初始化Cipher對象
cipher.init(Cipher.DECRYPT_MODE, key, spec);
// 獲取解密後的數據
byte decryptedData[] = cipher.doFinal(base64byte);
// 將解密後數據轉換爲字符串輸出
return new String(decryptedData);
}
}
2.AES:高級加密標準
AES算法用於替代DES,保護敏感信息,AES算法的分組長度爲128比特,其密鑰長度分別爲128比特,192比特,256比特。
/**
* AES:高級加密標準
* AES算法用於替代DES,保護敏感信息,AES算法的分組長度爲128比特,其密鑰長度分別爲128比特,192比特,256比特。
*/
public class AESUtil {
// 採用對稱分組密碼體制,密鑰長度的最少支持爲128、192、256
String key = "abcdefghijklmnop";
// 初始化向量參數,AES 爲16bytes. DES 爲8bytes, 16*8=128
String initVector = "0000000000000000";
IvParameterSpec iv;
SecretKeySpec skeySpec;
Cipher cipher;
private static class HOLDER {
private static AESUtil instance = new AESUtil();
}
public static AESUtil getInstance() {
return HOLDER.instance;
}
private AESUtil() {
try {
iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
// 這是CBC模式
// cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
// 默認就是ECB模式
cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public String encrypt(String value) {
try {
// CBC模式需要傳入向量,ECB模式不需要
// cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeToString(encrypted, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String decrypt(String encrypted) {
try {
// CBC模式需要傳入向量,ECB模式不需要
// cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
AES和DES在SecretKeySpec和Cipher創建的時候有不同,Cipher傳入的參數"AES/ECB/PKCS5PADDING"分別是“算法/工作模式/填充模式”,工作模式默認是ECB,不需要偏移,也就不需要傳入向量,而CBC和OFB是帶偏移的,需要傳入向量。
- 非對稱加密算法
非對稱加密是指加解密使用不同的祕鑰,即公鑰和私鑰。私鑰只能由一方安全保管,不能外泄,而公鑰則可以發給任何請求它的人。非對稱加密使用這對密鑰中的一個進行加密,而解密則需要另一個密鑰。比如你向銀行請求將公鑰公鑰發給你,並使用公鑰對消息加密,那麼只有持有私鑰的銀行才能對你的消息解密。與對稱加密不同的是,私鑰不需要通過網絡發送出去,因此安全性大大提高。
非對稱加密主要是RSA算法,RSA加解密本身對明文或者密文的長度有限制,這裏我們的加密算法可以支持分段加解密。
/**
* 非對稱加密算法
*/
public class RSAUtil {
public static final String RSA = "RSA";
public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";
// 祕鑰默認長度
public static final int DEFAULT_KEY_SIZE = 2048;
// 當要加密的內容超過bufferSize,則採用partSplit進行分塊加密
public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();
// 當前祕鑰支持加密的最大字節數
public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;
// 隨機生成RSA密鑰對,密鑰長度,範圍:512~2048
public static KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keyLength);
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 私鑰加密
* @param data 待加密數據
* @param privateKey 密鑰
* @return byte[] 加密數據
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
// 得到私鑰
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 數據加密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
return cipher.doFinal(data);
}
// 使用私鑰進行解密
public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
// 得到私鑰
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 解密數據
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.DECRYPT_MODE, keyPrivate);
byte[] arr = cp.doFinal(encrypted);
return arr;
}
// 用公鑰對字符串進行加密
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 加密數據
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.ENCRYPT_MODE, keyPublic);
return cp.doFinal(data);
}
/**
* 公鑰解密
* @param data 待解密數據
* @param publicKey 密鑰
* @return byte[] 解密數據
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公鑰
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 數據解密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.DECRYPT_MODE, keyPublic);
return cipher.doFinal(data);
}
// 以下開始分段解密
// 使用私鑰分段解密
public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPrivateKey(encrypted, privateKey);
}
int dataLen = encrypted.length;
List<Byte> allBytes = new ArrayList<Byte>(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最後了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part, privateKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 這個是以split[0]開頭
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 沒有超出data的範圍
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 驗證到split的最後一位,都沒有break,則表明已經確認是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,則已經匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part, privateKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
// 私鑰分段加密
public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return encryptByPrivateKey(data, privateKey);
}
List<Byte> allBytes = new ArrayList<Byte>(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
// 用公鑰對字符串進行分段加密
public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception {
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return encryptByPublicKey(data, publicKey);
}
List<Byte> allBytes = new ArrayList<Byte>(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPublicKey(buf, publicKey);
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
// 公鑰分段解密
public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPublicKey(encrypted, publicKey);
}
int dataLen = encrypted.length;
List<Byte> allBytes = new ArrayList<Byte>(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最後了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 這個是以split[0]開頭
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 沒有超出data的範圍
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 驗證到split的最後一位,都沒有break,則表明已經確認是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,則已經匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
}