android对文件进行加密

最开始想的是对apk进行加密,但是搜到的资料都是对dex层面的加密,后来转念一想,apk也可以被看做是一个普通的文件,普通的文件其实是可以使用AES进行加密的(AES比DES安全性和速度要更好,属于对称性加密里面很好的了),代码如下

fun main(args: Array<String>) {
	// key也可以采用下边的FileAESUtil.getAutoCreateAESKey()方法自动生成
    val key = "asdfghjkl"
    val content = "plugin.apk"
    val encryptMode = AESUtil.aes(content, key, Cipher.ENCRYPT_MODE)
    System.out.println("加密之后:" + encryptMode)

    // 解密
    val decryptMode = AESUtil.aes(encryptMode,key,Cipher.DECRYPT_MODE);
    System.out.println("解密之后:" + decryptMode)

    // 源文件
    val sourceFile = "F:\\app-debug.apk"
    // 加密输出的目标文件
    val targetFile = "F:\\a.apk"
    // 解密输出的目标文件
    val sourceDecryptFile = "F:\\target\\plugin.apk"

    val autoCreateKey = FileAESUtil.getAutoCreateAESKey()
    FileAESUtil.aesEncryptFile(sourceFile,targetFile,autoCreateKey);
    System.out.println("加密完成")
    FileAESUtil.aesDecryptFile(targetFile,sourceDecryptFile,autoCreateKey)
    System.out.println("解密完成")

}

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.SecureRandom;

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

public class FileAESUtil {

    private static String ALGORITHM_AES = "AES";
    private static int AES_KEY_LEN = 128;


    public static byte[] getAutoCreateAESKey() throws Exception {

        // 实例化一个AES加密算法的密钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
        // 初始化密钥生成器,指定密钥位数为128位
        keyGenerator.init(AES_KEY_LEN, new SecureRandom());
        // 生成一个密钥
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    /** AES加密
     *
     * @param sourceFile 源文件
     * @param encryptFile 加密文件
     * @param password 密钥,128bit
     * @throws Exception 抛出异常
     */
    public static void aesEncryptFile(String sourceFile, String encryptFile, byte[] password) throws Exception {

        // 创建AES密钥
        SecretKeySpec key = new SecretKeySpec(password,  "AES");
        // 创建加密引擎(CBC模式)。Cipher类支持DES,DES3,AES和RSA加加密
        // AES:算法名称
        // CBC:工作模式
        // PKCS5Padding:明文块不满足128bits时填充方式(默认),即在明文块末尾补足相应数量的字符,
        // 且每个字节的值等于缺少的字符数。另外一种方式是ISO10126Padding,除最后一个字符值等于少的字符数
        // 其他字符填充随机数。
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        // 初始化加密器
        cipher.init(Cipher.ENCRYPT_MODE, key,
                new IvParameterSpec(new byte[cipher.getBlockSize()]));
        // 原始文件流
        FileInputStream inputStream = new FileInputStream(sourceFile);
        // 加密文件流
        FileOutputStream outputStream = new FileOutputStream(encryptFile);
        // 以加密流写入文件
        CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
        byte[] tmpArray = new byte[1024];
        int len;
        while((len = cipherInputStream.read(tmpArray)) != -1) {

            outputStream.write(tmpArray, 0, len);
            outputStream.flush();
        }
        cipherInputStream.close();
        inputStream.close();
        outputStream.close();
    }

    /** AES解密
     *
     * @param encryptFile 加密文件
     * @param decryptFile 解密文件
     * @param password 密钥,128bit
     * @throws Exception 抛出异常
     */
    public static void aesDecryptFile(String encryptFile, String decryptFile, byte[] password) throws Exception {

        // 创建AES密钥,即根据一个字节数组构造一个SecreteKey
        // 而这个SecreteKey是符合指定加密算法密钥规范
        SecretKeySpec key = new SecretKeySpec(password,   "AES");
        // 创建解密引擎(CBC模式)
        // Cipher类支持DES,DES3,AES和RSA加解密
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        // 初始化解密器
        cipher.init(Cipher.DECRYPT_MODE, key,
                new IvParameterSpec(new byte[cipher.getBlockSize()]));
        // 加密文件流
        FileInputStream fileInputStream = new FileInputStream(encryptFile);
        // 解密文件流
        FileOutputStream fileOutputStream = new FileOutputStream(decryptFile);
        // 以解密流写出文件
        CipherOutputStream cipherOutputStream =
                new CipherOutputStream(fileOutputStream, cipher);
        byte[] buffer = new byte[1024];
        int len;
        while((len = fileInputStream.read(buffer)) >= 0) {

            cipherOutputStream.write(buffer, 0, len);
        }
        cipherOutputStream.close();
        fileInputStream.close();
        fileOutputStream.close();
    }

}

字符串加密

import java.security.Provider;
/**
 * Implementation of Provider for SecureRandom. The implementation     supports the
 * "SHA1PRNG" algorithm described in JavaTM Cryptography Architecture, API
 * Specification & Reference
 */
public final 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");
    }
}


import android.annotation.SuppressLint;
import android.os.Build;

import androidx.annotation.IntDef;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;



/**
 * AES 工具类
 */
public class AESUtil {
    private final static String SHA1PRNG = "SHA1PRNG";

    @IntDef({Cipher.ENCRYPT_MODE, Cipher.DECRYPT_MODE})
    @interface AESType {}

    /**
     * Aes加密/解密
     *
     * @param content  字符串
     * @param password 密钥
     * @param type     加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
     * @return 加密/解密结果字符串
     */
    public static String aes(String content, String password, @AESType int type) {
        try {
            KeyGenerator generator = KeyGenerator.getInstance("AES");

            SecureRandom secureRandom;
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                secureRandom = SecureRandom.getInstance(SHA1PRNG, new CryptoProvider());
            } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                secureRandom = SecureRandom.getInstance(SHA1PRNG, "Crypto");
            } else {
                secureRandom = SecureRandom.getInstance(SHA1PRNG);
            }
            secureRandom.setSeed(password.getBytes());
            generator.init(128, secureRandom);
            SecretKey secretKey = generator.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            @SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("AES");
            cipher.init(type, key);

            if (type == Cipher.ENCRYPT_MODE) {
                byte[] byteContent = content.getBytes("utf-8");
                return parseByte2HexStr(cipher.doFinal(byteContent));
            } else {
                byte[] byteContent = parseHexStr2Byte(content);
                return new String(cipher.doFinal(byteContent));
            }
        } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException |
                UnsupportedEncodingException | InvalidKeyException | NoSuchPaddingException |
                NoSuchProviderException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 二进位组转十六进制字符串
     *
     * @param buf 二进位组
     * @return 十六进制字符串
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuilder sb = new StringBuilder();
        for (byte b : buf) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 十六进制字符串转二进位组
     *
     * @param hexStr 十六进制字符串
     * @return 二进位组
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) return null;
        byte[] result = new byte[hexStr.length() / 2];

        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

}

遇到Didn’t find class “org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl”
可以使用下边链接解决
https://7449.github.io/2018/12/11/android-p-aes.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 混淆SO文件是指对Android native执行文件(.so文件)中的函数和数据进行加密和混淆,以保护代码的安全性和隐私性。与Java代码混淆不同的是,SO文件的混淆是在编译阶段完成的,而不是在打包和发布阶段。 在Android开发中,NDK(Native Development Kit)是一款可用于编写本地代码的工具集。使用NDK开发的应用程序使用SO文件来提供C/C++函数和库。由于NDK代码不会在应用程序中进行编译,因此它们没有类似于Java代码的混淆和加密工具。因此,为了加强SO文件的安全性,需要使用其他的工具来进行混淆。 现在有许多开源的SO混淆工具可供使用。例如,Android NDK提供了一个名为LLVM混淆器的工具,它使用一些与Java代码混淆器不同的技术来优化指令流和掩盖代码逻辑。此外,其他SO混淆工具如YASC、MOVfuscator、O-LLVM等也可以用于混淆SO文件。 SO文件混淆可以通过多种方式实现。例如,针对代码文件进行重命名或修改,删除未引用的函数和数据,加密和混淆重要内容等。此外,也可以通过将硬编码的值替换为映射的值,使用一些外部定义的数据结构来防止反汇编和静态分析等技术来实现混淆。无论采用何种方法,SO文件混淆对于保护代码的安全性和隐私性都具有重要意义。 ### 回答2: 使用Android Studio中的ProGuard工具可以对一个应用程序的Java class文件进行混淆,但是它并不支持对Native代码的混淆。由于so文件是编译后的二进制文件,没有人可读的,对so文件进行混淆通常都是为了防止逆向工程而不是优化程序的运行或缩小它的大小。 现在有一些第三方工具可以用来对so文件进行混淆,比如Bangcle、Qihoo 360、Baidu和信鸽。这些工具通过改变so文件的代码结构、函数名称和变量名等方法来混淆so文件,使之更加难以阅读和理解。 混淆so文件是有一定风险的,因为这可能会导致应用程序的崩溃和功能异常。此外,混淆so文件可能会和某些平台实现产生不兼容的问题。但是如果您确实担心你的so文件受到攻击,那么混淆so文件可能是一个值得考虑的安全策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值