自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android外部文件加解密及應(yīng)用實(shí)踐

移動開發(fā) Android
有這樣的應(yīng)用場景,當(dāng)我們把一些重要文件放到asset文件夾中時(shí),把.apk解壓是可以直接拿到這個(gè)文件的,一些涉及到重要信息的文件我們并不想被反編譯拿去,這個(gè)時(shí)候需要先對文件進(jìn)行加密,然后放到Android中的資源目錄下,用的時(shí)候再解密出來。

有這樣的應(yīng)用場景,當(dāng)我們把一些重要文件放到asset文件夾中時(shí),把.apk解壓是可以直接拿到這個(gè)文件的,一些涉及到重要信息的文件我們并不想被反編譯拿去,這個(gè)時(shí)候需要先對文件進(jìn)行加密,然后放到Android中的資源目錄下,用的時(shí)候再解密出來。

現(xiàn)代密碼學(xué)中,加密系統(tǒng)的安全性是基于密鑰的,而不是基于算法,現(xiàn)在介紹一整套加解密及應(yīng)用流程,這套加密流程從實(shí)用性和安全性上來講,我覺得還是很靠譜的,也是市面上比較常用的做法,核心邏輯其實(shí)比較簡單,畢竟最難的加解密算法實(shí)現(xiàn)部分是現(xiàn)成的了,我司部分也用了這套流程,當(dāng)然會比我講的這個(gè)要復(fù)雜一些。

1、簡介

主要涉及到一下幾個(gè)算法的應(yīng)用,RSA、AES,以及Base64編碼,基本思想是用[AES算法+AES密鑰]來加密文件,為了保證密鑰的安全性,會通過[RSA算法+RSA私鑰]對AES密鑰進(jìn)行加密。

對這幾種算法不熟悉可以看看我司大佬的‘常用的加密方式和應(yīng)用場景’這篇文章,知道大概的原理和使用方法就行,因?yàn)樗惴ㄔ趈ava中都是現(xiàn)成的,直接拿來用就是了。 

Android外部文件加解密及應(yīng)用實(shí)踐

Android加解密流程圖.png

 

把流程整理了一下,就是以上的流程圖,分成三塊:

  • 第1塊是把加密過程給封裝成一個(gè)小工具,用加密工具來對文件進(jìn)行加密;
  • 第2塊是把解密過程封裝成解密的小工具,用解密工具來解密我們的文件好進(jìn)行相關(guān)修改;
  • 第3塊使我們的目的,就是把加密文件和加解密的AES算法密鑰放到Android資源文件中進(jìn)行具體的使用。

有一點(diǎn)需要補(bǔ)充的,就是RSA算法的公私鑰,從第3塊中可以發(fā)現(xiàn),并沒有把RSA的公鑰和私鑰放到資源文件中,其實(shí)大家想想就知道了,如果被加密文件、加解密的AES密鑰、用于對AES密鑰進(jìn)行加密的RSA密鑰三者都放入文件夾中,那就沒有啥安全性可言了(注:加解密的算法可以改造成自己公司獨(dú)有的,我司就是這么做的),所以為了保證安全性,我們的RSA公私鑰是通過應(yīng)用的簽名(.keystore簽名文件)中代碼動態(tài)獲取。感興趣的可以看這篇文章:[從Java Keystore文件中提取私鑰、證書]。

2、第1塊:加密工具進(jìn)行加密

工具的java界面開發(fā)是通過java的swing包來實(shí)現(xiàn)的,對swing感興趣的可以參考這篇Java Swing 圖形界面開發(fā)簡介,講得非常詳細(xì)。

一開始的時(shí)候是沒有AES秘鑰的,需要我們生成一個(gè)安全的秘鑰,所以生成一個(gè)隨機(jī)AES秘鑰,然后保存,加密工具的操作頁界面: 

Android外部文件加解密及應(yīng)用實(shí)踐

加密

 

2.1、生成隨機(jī)秘鑰

生成隨機(jī)秘鑰主要分為幾步:

  • 通過UUID.randomUUID()生成隨機(jī)數(shù)作為seed種子;
  • seed種子提供給KeyGenerator生成AES秘鑰,只要seed種子生成的AES秘鑰就是一致的;
  • 通過應(yīng)用簽名獲取RSA算法需要的公鑰私鑰;
  • RSA通過私鑰來加密AES秘鑰;

因?yàn)樯傻拿罔€是byte[],所以通過Base64編碼展示出來給到界面上。 

  1. /**  
  2. * 生成隨機(jī)密鑰  
  3. */  
  4. private void randomKey() {  
  5. try {  
  6. //生成隨機(jī)數(shù)作為seed種子  
  7. String uuid = UUID.randomUUID().toString();  
  8. byte[] seed = uuid.getBytes("UTF-8");  
  9. //生成AES秘鑰  
  10. byte[] rawkey = AES.getRawKey(seed);  
  11. //獲取應(yīng)用簽名的密鑰對  
  12. KeyPair pair = SignKey.getSignKeyPair();  
  13. //通過RSA私鑰來加密AES秘鑰  
  14. byte[] key = RSA.encrypt(rawkey, pair.getPrivate());  
  15. //Base64編碼成字符串展示  
  16. String base64Key = Base64.encode(key);  
  17. mKeyText.setText(base64Key);  
  18. } catch (Exception e) {  
  19. e.printStackTrace();  
  20.  
  21.  
  22. 其中AES.getRawKey(seed)中主要是通過AES密鑰生成器來生成128位的密鑰,具體實(shí)現(xiàn):  
  23. /** 
  24.  * 生成用AES算法來加密的密鑰流,這個(gè)密鑰會被應(yīng)用簽名{@link SignKey}的密鑰進(jìn)行二次加密  
  25. */  
  26. public static byte[] getRawKey(byte[] seed) throws Exception {  
  27. KeyGenerator kgen = KeyGenerator.getInstance("AES");  
  28. SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");  
  29. sr.setSeed(seed);  
  30. //192 and 256 bits may not be available  
  31. kgen.init(128, sr);  
  32. SecretKey skey = kgen.generateKey();  
  33. return skey.getEncoded();  

SignKey.getSignKeyPair()是獲得RSA算法所需的公私鑰,是從我們的應(yīng)用簽名來的,大家應(yīng)該都很熟悉了,應(yīng)用打包上傳是需要簽名打包的。 

Android外部文件加解密及應(yīng)用實(shí)踐

keystore

 

java提供了api獲取testkey.keystore文件(自己用studio生成一個(gè))的私鑰和證書,把testkey.keystore文件放到目錄中: 

  1. /**  
  2. * Author:xishuang  
  3. Date:2018.05.06  
  4. * Des:根據(jù)導(dǎo)入的應(yīng)用簽名,讀取其中的密鑰對和證書  
  5. */  
  6. public class SignKey {  
  7. //應(yīng)用簽名  
  8. private static final String keystoreName = "testkey.keystore" 
  9. private static final String keystorePassword = "123456" 
  10. //應(yīng)用簽名的別名  
  11. private static final String alias = "key0" 
  12. private static final String aliasPassword = "123456" 
  13. /**  
  14. * 獲取簽名的密鑰對,用來給密鑰加密  
  15. */  
  16. public static KeyPair getSignKeyPair() {  
  17. try {  
  18. File storeFile = new File(keystoreName);  
  19. if (!storeFile.exists()) {  
  20. throw new IllegalArgumentException("還沒設(shè)置簽名文件!");  
  21.  
  22. String keyStoreType = "JKS" 
  23. char[] keystorepasswd = keystorePassword.toCharArray();  
  24. char[] keyaliaspasswd = aliasPassword.toCharArray();  
  25. KeyStore keystore = KeyStore.getInstance(keyStoreType);  
  26. keystore.load(new FileInputStream(storeFile), keystorepasswd);  
  27. //拿私鑰  
  28. Key key = keystore.getKey(alias, keyaliaspasswd);  
  29. if (key instanceof PrivateKey) {  
  30. //拿公鑰  
  31. Certificate cert = keystore.getCertificate(alias);  
  32. PublicKey publicKey = cert.getPublicKey();  
  33. ///公私鑰存到KeyPair 
  34.  return new KeyPair(publicKey, (PrivateKey) key);  
  35.  
  36. } catch (Exception e) {  
  37. e.printStackTrace();  
  38.  
  39. return null 
  40.  

拿testkey.keystore所需的參數(shù)都在跟我們打包應(yīng)用簽名所需一樣,通過java提供的keystore類獲取。然后就是用剛拿到的testkey.keystore私鑰來加密AES密鑰,再通過Base64轉(zhuǎn)換一下編碼成字符串展示出來,只是為了把密鑰展示出來才轉(zhuǎn)換編碼的。 

Android外部文件加解密及應(yīng)用實(shí)踐

密鑰Base64編碼.png

 

2.2、導(dǎo)出密鑰

把密鑰導(dǎo)出成文件,下次直接導(dǎo)入密鑰用來解密文件,導(dǎo)出密鑰需要先用Base64把文本框里的Base64密鑰字符串轉(zhuǎn)換為Byte[]再存。 

  1. byte[] key = Base64.decode(base64Key);  
  2. //將raw key輸出  
  3. File keyFile = new File(dir, "testkey.dat");  
  4. FileOutputStream fos = new FileOutputStream(keyFile); 

2.3、加密文件

密鑰已有,AES算法又是現(xiàn)成的,直接調(diào)用api加密就行了: 

  1. private static final String AES = "AES" 
  2. /**  
  3. * AES算法加密文件  
  4.  
  5. * @param rawKey AES密鑰  
  6. * @param fromFile 要加密的文件  
  7. * @param toFile 加密后文件  
  8. */  
  9. public static void encryptFile(byte[] rawKey, File fromFile, File toFile) throws Exception {  
  10. if (!fromFile.exists()) {  
  11. throw new NullPointerException("文件不存在");  
  12.  
  13. if (toFile.exists()) {  
  14. toFile.delete();  
  15.  
  16. SecretKeySpec skeySpec = new SecretKeySpec(rawKey, AES);  
  17. Cipher cipher = Cipher.getInstance(AES); 
  18.  //加密模式  
  19. cipher.init(Cipher.ENCRYPT_MODE, skeySpec);  
  20. FileInputStream fis = new FileInputStream(fromFile);  
  21. FileOutputStream fos = new FileOutputStream(toFile, true);  
  22. byte[] buffer = new byte[512 * 1024 - 16];  
  23. int offset; 
  24. //使用加密流來加密  
  25. CipherInputStream bis = new CipherInputStream(fis, cipher);  
  26. while ((offset = bis.read(buffer)) != -1) { 
  27.  fos.write(buffer, 0, offset);  
  28. fos.flush();  
  29.  
  30. fos.close();  
  31. fis.close();  

選擇文件,通過AES算法和AES密鑰加密,最后效果如下,沒有密鑰能解密出來算我輸。 

Android外部文件加解密及應(yīng)用實(shí)踐

加密前后

 

3、第2塊:解密工具進(jìn)行解密

解密過程其實(shí)沒啥必要講了,因?yàn)榻饷苓^程是加密過程的逆過程。

這個(gè)解密不是在應(yīng)用中用的,是為了便于我們更新加密文件,修改文件之前必須要先把文件先解密。 

Android外部文件加解密及應(yīng)用實(shí)踐

解密

 

3.1、導(dǎo)入AES密鑰

這個(gè)密鑰就是我們前面生成的密鑰,導(dǎo)進(jìn)來后用應(yīng)用簽名的RSA公鑰解密AES密鑰即可:

 

  1. //獲取被加密的密鑰raw key  
  2. String keyStr = mKeyText.getText(); 
  3. byte[] key = Base64.decode(keyStr);  
  4. //獲取應(yīng)用簽名密鑰對,公鑰解密raw key  
  5. KeyPair keypair = SignKey.getSignKeyPair();  
  6. byte[] rawkey = RSA.decrypt(key, keypair.getPublic());  
  7. //用raw key去解密文件  
  8. AES.decryptFile(rawkey, fromFile, toFile); 

3.2、解密文件

拿到純潔版AES密鑰之后就可以直接調(diào)用AES算法解密文件了: 

  1. /**  
  2. * AES算法解密文件  
  3.  
  4. * @param rawKey AES密鑰  
  5. * @param fromFile 被加密的文件  
  6. * @param toFile 解密后文件  
  7. */  
  8. public static void decryptFile(byte[] rawKey, File fromFile, File toFile) throws Exception {  
  9. if (!fromFile.exists()) {  
  10. throw new NullPointerException("文件不存在");  
  11.  
  12. if (toFile.exists()) {  
  13. toFile.delete();  
  14.  
  15. SecretKeySpec skeySpec = new SecretKeySpec(rawKey, AES);  
  16. Cipher cipher = Cipher.getInstance(AES);  
  17. //解密模式  
  18. cipher.init(Cipher.DECRYPT_MODE, skeySpec);  
  19. FileInputStream fis = new FileInputStream(fromFile);  
  20. FileOutputStream fos = new FileOutputStream(toFile, true);  
  21. byte[] buffer = new byte[512 * 1024 + 16];  
  22. int offset;  
  23. //使用解密流來解密  
  24. CipherInputStream cipherInputStream = new CipherInputStream(fis, cipher);  
  25. while ((offset = cipherInputStream.read(buffer)) != -1) {  
  26. fos.write(buffer, 0, offset);  
  27. fos.flush();  
  28.  
  29. fos.close();  
  30. fis.close();  

和AES加密過程一對比,會發(fā)現(xiàn)只是切換一下AES算法模式。

3、第3塊:Android應(yīng)用中解密文件

要解密文件,需要在資源文件夾中加入被加密的AES密鑰,這個(gè)密鑰就是上面導(dǎo)出來的,還有就是被加密后的文件。能正確解密的前提是你應(yīng)用簽名和用來給文件加密過程中用到的簽名是同一個(gè)。 

Android外部文件加解密及應(yīng)用實(shí)踐

資源文件

 

3.1、解密AES密鑰

在Android應(yīng)用中解密文件與在java工具中解密文件,區(qū)別主要在于RSA密鑰的獲取,在java工具中應(yīng)用簽名testkey.keystore是開發(fā)者擁有的,可以拿到其中的全部信息,而在Android中應(yīng)用是要發(fā)布到應(yīng)用市場的,任何人都可以下載我們的包,應(yīng)用簽名只能通過Android提供的api拿到其公鑰。 

  1. /**  
  2. * Author:xishuang  
  3. Date:2018.05.06  
  4. * Des:應(yīng)用簽名讀取工具類  
  5. */  
  6. public class SignKey {  
  7. /**  
  8. * 獲取當(dāng)前應(yīng)用的簽名  
  9.  
  10. * @param context 上下文  
  11. */  
  12. public static byte[] getSign(Context context) {  
  13. PackageManager pm = context.getPackageManager(); 
  14. try {  
  15. PackageInfo info = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);  
  16. Signature[] signatures = info.signatures;  
  17. if (signatures != null) {  
  18. return signatures[0].toByteArray();  
  19.  
  20. } catch (NameNotFoundException e) {  
  21. e.printStackTrace();  
  22.  
  23. return null 
  24.  
  25. /**  
  26. * 根據(jù)簽名去獲取公鑰  
  27. */  
  28. public static PublicKey getPublicKey(byte[] signature) {  
  29. try {  
  30. CertificateFactory certFactory = CertificateFactory  
  31. .getInstance("X.509");  
  32. X509Certificate cert = (X509Certificate) certFactory  
  33. .generateCertificate(new ByteArrayInputStream(signature));  
  34. return cert.getPublicKey();  
  35. } catch (CertificateException e) {  
  36. e.printStackTrace();  
  37.  return null 
  38.  

拿到應(yīng)用簽名testkey.keystore的公鑰之后的流程就和在java工具中的操作基本一致了,用RSA公鑰來解密AES密鑰。 

  1. private static final String SIMPLE_KEY_DATA = "testkey.dat" 
  2. /**  
  3. * 獲取解密之后的文件加密密鑰  
  4. */  
  5. private static byte[] getRawKey(Context context) throws Exception {  
  6. //獲取應(yīng)用的簽名密鑰  
  7. byte[] sign = SignKey.getSign(context);  
  8. PublicKey pubKey = SignKey.getPublicKey(sign);  
  9. //獲取加密文件的密鑰  
  10. InputStream keyis = context.getAssets().open(SIMPLE_KEY_DATA);  
  11. byte[] key = getData(keyis);  
  12. //解密密鑰  
  13. return RSA.decrypt(key, pubKey);  

最后再用解密之后的AES密鑰來解密文件。

3.2、AES密鑰解密文件

通過資源管理器拿到加密文件的文件流,通過AES密鑰來用AES算法來解密文件流。 

  1. /**  
  2. * 獲取解密之后的文件流  
  3. */  
  4. public static InputStream onObtainInputStream(Context context) {  
  5. try {  
  6. AssetManager assetmanager = context.getAssets();  
  7. InputStream is = assetmanager.open("encrypt_測試.txt");  
  8. byte[] rawkey = getRawKey(context);  
  9. //使用解密流,數(shù)據(jù)寫出到基礎(chǔ)OutputStream之前先對該會先對數(shù)據(jù)進(jìn)行解密  
  10. SecretKeySpec skeySpec = new SecretKeySpec(rawkey, "AES");  
  11. Cipher cipher = Cipher.getInstance("AES");  
  12. cipher.init(Cipher.DECRYPT_MODE, skeySpec);  
  13. return new CipherInputStream(is, cipher);  
  14. } catch (Exception e) {  
  15. e.printStackTrace();  
  16.  
  17. return null 

拿到加密后文件流之后就達(dá)成目的了,可以解析成字符串展示出來: 

  1. private void inputData() {  
  2. InputStream in = DecryptUtil.onObtainInputStream(this);  
  3. try {  
  4. BufferedReader reader = new BufferedReader(new InputStreamReader(in"GBK"));  
  5. StringBuilder sb = new StringBuilder();  
  6. String line;  
  7. while ((line = reader.readLine()) != null) {  
  8. sb.append(line + "\n");  
  9.  
  10. contentTv.setText(sb.toString());  
  11. } catch (IOException e) {  
  12. e.printStackTrace();  
  13. } finally {  
  14. try {  
  15. in.close();  
  16. } catch (IOException e) {  
  17. e.printStackTrace();  
  18.  
  19.  

實(shí)例效果圖如下,請關(guān)注紅框里面內(nèi)容,因?yàn)閼械眯陆?xiàng)目,用原有項(xiàng)目測試了一下: 

Android外部文件加解密及應(yīng)用實(shí)踐

效果

 

目前工具使用的是市面上比較常見的加解密算法,可以換一下算法,比如DES或者其它的對稱和非對稱算法,甚至是自己改動的算法,想運(yùn)行示例演示的話: 

Android外部文件加解密及應(yīng)用實(shí)踐

QQ截圖20180508234849.png

 

就是運(yùn)行一下java文件,就可以打開加解密小工具了,加解密工具界面是仿我司工具包中抽出來的小部分的,畢竟寫界面好煩,感謝我司大神多年前就寫出了如此工具。

責(zé)任編輯:未麗燕 來源: 簡書
相關(guān)推薦

2017-12-07 10:25:55

LinuxGPG加密解密

2015-02-11 15:23:13

微信SDK

2015-02-11 15:27:26

微信SDK

2020-12-13 09:40:11

物聯(lián)網(wǎng)物聯(lián)網(wǎng)安全加密方法

2016-09-27 19:30:11

2022-01-26 07:25:09

PythonRSA加解密

2013-11-15 13:06:52

透明加解密hook技術(shù)數(shù)據(jù)安全

2011-08-01 14:36:06

加密RSA

2022-07-27 08:49:34

接口加密解密

2021-12-15 14:39:50

LinuxGPG加解密文件

2024-09-27 15:24:15

Spring數(shù)據(jù)加解密

2024-09-09 08:53:56

2022-11-18 18:36:24

2023-03-10 18:34:31

2022-09-14 18:23:01

工具加解密接口

2022-12-14 09:06:58

接口Spring解密

2017-02-09 11:34:57

大數(shù)據(jù)用戶畫像應(yīng)用實(shí)踐

2010-03-02 11:12:33

Android應(yīng)用開發(fā)

2012-12-03 10:59:30

2015-02-11 15:56:20

微信SDK
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號