大家好,又见面了,我是你们的朋友全栈君。
最开始想的是对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;
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/145699.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...