常用的加密方式和应用场景

区别和使用场景

Posted by Jack on April 16, 2019

常用的加密方式和应用场景

1.前言

在移动端的开发中,数据安全的问题一直是大家备受关注的,数据加密技术也受到了大家的青睐。项目中也用到了一些,在这里学习总结下,完善下自己的知识,也分享给大家,一起交流!

  • 按可逆性:加密可分为可逆算法不可逆算法
  • 按对称性:加密可分为对称算法非对称算法

一般的加密分为以下几种,下面会分别简单讲解原理和其使用方法:

  • Base64编码算法 (可逆)
  • MD5加密 (不可逆)(还有一个sha1值,可能做过支付宝的会比较熟悉)
  • Des加密 (对称,可逆)
  • Aes加密 (对称,可逆)
  • Rsa加密(非对称,可逆)

2.浅谈对称非对称

对称

对称加密算法是较传统的加密体制,即通信双方在加/解密过程中使用他们共享的单一密钥,鉴于其算法简单加密速度快的优点,目前仍然在使用,但是安全性方面就差一点可能。最常用的对称密码算法是DES算法,而DES密钥长度较短,已经不适合当今分布式开放网络对数据加密安全性的要求。一种新的基于Rijndael算法(自己脑补,本人也不太熟悉)对称高级数据加密标准AES取代了数据加密标准DES,弥补了DES的缺陷,目前使用比较多一点

非对称

非对称加密由于加/解密钥不同(公钥加密,私钥解密),密钥管理简单,得到了很广泛的应用。RSA是非对称加密系统最著名的公钥密码算法。但是由于RSA算法进行的都是大数计算,使得RSA最快的情况也比AES慢上倍,这是RSA最大的缺陷。但是其安全性较高,这也是大家比较喜欢的地方吧!

3.各算法介绍

3.1 Base64算法

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64并不是安全领域的加密算法,其实Base64只能算是一个编码算法,对数据内容进行编码来适合传输。标准Base64编码解码无需额外信息即完全可逆,即使你自己自定义字符集设计一种类Base64的编码方式用于数据加密,在多数场景下也较容易破解。Base64编码本质上是一种将二进制数据转成文本数据的方案。对于非二进制数据,是先将其转换成二进制形式,然后每连续6比特(2的6次方=64)计算其十进制值,根据该值在A–Z,a–z,0–9,+,/ 这64个字符中找到对应的字符,最终得到一个文本字符串。基本规则如下几点:

  1. 标准Base64只有64个字符(英文大小写、数字和+、/)以及用作后缀等号;
  2. Base64是把3个字节变成4个可打印字符,所以Base64编码后的字符串一定能被4整除(不算用作后缀的等号);
  3. 等号一定用作后缀,且数目一定是0个、1个或2个。这是因为如果原文长度不能被3整除,Base64要在后面添加\0凑齐3n位。为了正确还原,添加了几个\0就加上几个等号。显然添加等号的数目只能是0、1或2;
  4. 严格来说Base64不能算是一种加密,只能说是编码转换。

Base64编码一般用于url的处理

下图为base64编码表

  • 字符串进行Base64编码
   String encodedString = Base64.encodeToString("testtest".getBytes(), Base64.DEFAULT);
   Log.e("Base64", "Base64---->" + encodedString);
  • 字符串进行Base64解码
    String decodedString =new String(Base64.decode(encodedString,Base64.DEFAULT));
    Log.e("Base64", "Base64---->" + decodedString);
  • Base64.DEFAULT参数说明
   1.DEFAULT 这个参数是默认,使用默认的方法来加密
   2.NO_PADDING 这个参数是略去加密字符串最后的”=”
   3.NO_WRAP 这个参数意思是略去所有的换行符(设置后CRLF就没用了)
   4.CRLF 这个参数看起来比较眼熟,它就是Win风格的换行符,意思就是使用CR LF这一对作为 一行的结尾而不是Unix风格的LF
   5.URL_SAFE 这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符,具体就是以-和_取代+和/

3.2 MD5

MD5英文全称“Message-Digest Algorithm 5”,翻译过来是“消息摘要算法5”,由MD2、MD3、MD4演变过来的,它是一种单向加密算法,只能加密、无法解密。多用于密码的存储等等。对于MD5的安全性,网上有关MD5解密的网站数不胜数,破解机制采用穷举法,就是收集所有可能的MD5值跑字典。所以常常采用对数据进行多次MD5加密或者采取加盐(就是加一段独有的字符串在进行加密)的操作。

  • MD5加密有哪些特点?

    1) 压缩性:任意长度的数据,算出的MD5值长度都是固定的。

    2)容易计算:从原数据计算出MD5值很容易。

    3)抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

    4)强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

  • MD5应用场景:

    1)一致性验证(密码校验)

    2)数字签名

    3)安全访问认证

  • 算法实现:

3.2.1 计算字符串MD5值

 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());
        String result = "";
        for (byte b : bytes) {
            String temp = Integer.toHexString(b & 0xff);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            result += temp;
        }
        return result;
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

3.2.2 计算文件的MD5值

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

3.2.3 对字符串多次MD5加密

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

3.2.4 MD5加盐(加盐的方式也是多种多样)

1.string+key(盐值key)然后进行MD5加密

2.用string明文的hashcode作为盐,然后进行MD5加密

3.随机生成一串字符串作为盐,然后进行MD5加密

  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());
        String result = "";
        for (byte b : bytes) {
            String temp = Integer.toHexString(b & 0xff);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            result += temp;
        }
        return result;
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

3.3 AES加密

对称加密秘钥是唯一的,加密解密都是一个秘钥。AES速度上占优于RSA,但是只有一个秘钥,安全性较低一些。

3.3.1 AES加密的使用


import android.text.TextUtils;
import android.util.Base64;

import java.security.Provider;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESUtils {
    private final static String HEX = "0123456789ABCDEF";
    private  static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";//AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
    private  static final String AES = "AES";//AES 加密
    private  static final String  SHA1PRNG="SHA1PRNG";// SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法

    /**
     * 生成随机数,可以当做动态的密钥 加密和解密的密钥必须一致,不然将不能解密
     */
    public static String generateKey() {
        try {
            SecureRandom localSecureRandom = SecureRandom.getInstance(SHA1PRNG);
            byte[] bytes_key = new byte[20];
            localSecureRandom.nextBytes(bytes_key);
            String str_key = toHex(bytes_key);
            return str_key;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // 对密钥进行处理
    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        //for android
        SecureRandom sr = null;
        // 在4.2以上版本中,SecureRandom获取方式发生了改变
        int sdk_version = android.os.Build.VERSION.SDK_INT;
        if(sdk_version>23){  // Android  6.0 以上
            sr = SecureRandom.getInstance(SHA1PRNG,new CryptoProvider());
        }else if(android.os.Build.VERSION.SDK_INT >= 17){   //4.2及以上
            sr = SecureRandom.getInstance(SHA1PRNG, "Crypto");
        }else {
            sr = SecureRandom.getInstance(SHA1PRNG);
        }


        // for Java
        // secureRandom = SecureRandom.getInstance(SHA1PRNG);
        sr.setSeed(seed);
        kgen.init(128, sr); //256 bits or 128 bits,192bits
        //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }

    /*
     * 加密
     */
    public static String encrypt(String key, String cleartext) {
        if (TextUtils.isEmpty(cleartext)) {
            return cleartext;
        }
        try {
            byte[] result = encrypt(key, cleartext.getBytes());
//            return Base64Encoder.encode(result);
            return new String(Base64.encode(result,Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
    * 加密
    */
    private static byte[] encrypt(String key, byte[] clear) throws Exception {
        byte[] raw = getRawKey(key.getBytes());
        SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
        Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }
    /**
     * 解密
     */
    public static String decrypt(String key, String encrypted) {
        if (TextUtils.isEmpty(encrypted)) {
            return encrypted;
        }
        try {
//            byte[] enc = Base64Decoder.decodeToBytes(encrypted);
            byte[] enc = Base64.decode(encrypted,Base64.DEFAULT);
            byte[] result = decrypt(key, enc);
            return new String(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     */
    private static byte[] decrypt(String key, byte[] encrypted) throws Exception {
        byte[] raw = getRawKey(key.getBytes());
        SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
        Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }
    //二进制转字符
    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";
        StringBuffer result = new StringBuffer(2 * buf.length);
        for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
        }
        return result.toString();
    }

    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
    }


    // 增加  CryptoProvider  类

    public static  class CryptoProvider extends Provider {
        /**
         * Creates a Provider and puts parameters
         */
        public CryptoProvider() {
            super("Crypto", 1.0, "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)");
            put("SecureRandom.SHA1PRNG",
                    "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl");
            put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
        }
    }
}

3.3.2 github上的安卓AES加解密库

https://github.com/tozny/java-aes-crypto

这个库可以加 salt,使密码更安全

3.4 RSA加密

RSA算法是最流行的公钥密码算法,使用长度可以变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法。

RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,这是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥,但RSA仍然不失为一种高强度的算法。

  //几个常用变量
  public static final String RSA = "RSA";// 非对称加密密钥算法
  public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
  public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
  public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();    // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
  public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数

3.4.1 RSA加密的使用

第一步:首先生成秘钥对

    /**
 * 随机生成RSA密钥对
 *
 * @param keyLength 密钥长度,范围:512~2048
 *                  一般1024
 * @return
 */
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 原文
 */
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 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);
}

公钥解密

/**
 * 公钥解密
 *
 * @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[] 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;
}

但是这里需要注意的是android系统的RSA实现是“RSA/None/NoPadding”,而标准JDK实现是“RSA/None/PKCS1Padding” ,这造成了在android机上加密后无法在服务器上解密的原因,所以在实现的时候这个一定要注意。 RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes) , RSA 是常用的非对称加密算法,研究发现是由于待加密的数据超长所致。

RSA 算法规定:待加密的字节数不能超过密钥的长度值除以 8 再减去 11(即:KeySize / 8 - 11),而加密后得到密文的字节数,正好是密钥的长度值除以 8(即:KeySize / 8)。

公钥分段加密

/**
 * 用公钥对字符串进行分段加密
 *
 */
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;
}

私钥分段加密

/**
 * 分段加密
 *
 * @param data       要加密的原始数据
 * @param privateKey 秘钥
 */
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;
}

公钥分段解密

/**
 * 公钥分段解密
 *
 * @param encrypted 待解密数据
 * @param publicKey 密钥
 */
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;
}

私钥分段解密

/**
 * 使用私钥分段解密
 *
 */
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;
}

参考链接

浅谈android数据存储加密

常用的加密方式和应用场景

安卓AES加解密(兼容Android7.0)