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
版权声明:本文为u010648159原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。