摘要html
這篇文章原本早就應該寫了,可是因爲項目一直開發新的需求,就拖後了。如今有時間了,必須得寫了。如今Android應用程序對安全防範這方面要求愈來愈高了。特別是金融行業,若是金融app沒有沒有作好相應安全處理,那些很容易被一些Hacker(黑客)所攻擊。並非說作了這些安全防範,這個應用就百分之百的安全的。只是說可以儘量加大破解難度。也許有些開發者或者企業以爲。咱們公司的app,數據量這些少,會有那個黑客吃飽了沒事作來破解啊。又不是支付寶,或者其餘那些用戶量不少的應用。若是是這樣想的話,那隻能說目光短淺了。java
Android應用經常使用的加密算法android
若是說按加密的內容是否能夠還原,能夠分爲可逆加密和非可逆加密。算法
非可逆加密:也就是說加密後的數據是不能還原成原來的數據。好比MD5加密 加密一個密碼:123456 加密後成: afabsbfbabf437hfbbff73(結果並不必定是這個,只是舉例)。也就是說加密後的結果afabsbfbabf437hfbbff73是不可以在解密出123456這個值的。api
可逆加密:可逆加密有一個公鑰和一個私鑰,經過公鑰進行數據的加密,經過私鑰進行解密。表明有:RSA,AES。數組
對稱加密和非對稱加密:可逆加密根據其使用加解密是否使用同一個密鑰又分爲對稱加密(加解密使用同一個密鑰)和非對稱加密(加解密的密鑰分開)安全
MD5服務器
MD5的特色:app
一、壓縮性:任意長度的數據,算出來的MD5值的長度都是固定。dom
二、容易計算性:從原始數據計算出MD5值是很容易的。
三、抗修改性:願數據只要有一點點的改動,獲得的MD5差異都是很大的。
四、強抗碰撞性:從原數據計算出來的MD5,想要找到一個具備相同的MD5,很是難。
MD5的應用場景:
一、一致性驗證(好比下載某個文件,不知道文件是否下載完成,能夠MD5進行校驗。加密文件比較耗時,須要放到子線程中)
二、密碼的存儲(如登錄註冊這些,帳號密碼會保存到sp中,直接就保存到帳號密碼的MD5值就行了。這樣也能夠避免服務器權限者知道這個密碼)
MD5的簡單使用
先寫一個MD5的工具類
1 package com.example.huangjialin.md5test; 2 3 import java.io.UnsupportedEncodingException; 4 import java.security.MessageDigest; 5 import java.security.NoSuchAlgorithmException; 6 7 /** 8 * Created by huangjialin on 2018/9/4. 9 */ 10 11 public class Utils { 12 13 public static String md5(String content) { 14 byte[] hash = null; 15 try { 16 hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8")); 17 } catch (NoSuchAlgorithmException e) { 18 e.printStackTrace(); 19 } catch (UnsupportedEncodingException e) { 20 e.printStackTrace(); 21 } 22 23 StringBuilder stringBuilder = new StringBuilder(hash.length * 2); 24 for (byte b: hash) { 25 if ((b & 0xFF) < 0x10){ 26 stringBuilder.append("0"); 27 28 } 29 stringBuilder.append(Integer.toHexString(b & 0xFF)); 30 31 } 32 return stringBuilder.toString(); 33 } 34 35 }
簡單的解釋一下上面的,首先是經過MessageDigest.getInstance(「MD5」)來獲取到MessageDigest這個類,這個類是java自帶的一個加密類,而後經過調用digest()方法來的獲取到加密後的字節數組。該方法傳入的參數是byte[] input 因此還須要將字符串轉化爲byte[]。獲得加密後的字節數組之後,將他們轉換成16禁止的字符串,而後拼接起來就能夠了。
而後直接調用:
1 /** 2 3 * MD5加密 4 5 */ 6 7 button.setOnClickListener(new View.OnClickListener() { 8 9 @Override 10 11 public void onClick(View v) { 12 13 14 15 String md5_123456abc = Utils.md5("123456abc"); 16 17 String md5_huangjialin = Utils.md5("huangjialin"); 18 19 Log.i("huangjialin"," md5_123456abc算出的MD5值是: " + md5_123456abc); 20 21 Log.i("huangjialin"," md5_huangjialin算出的MD5值是: " + md5_huangjialin); 22 23 } 24 25 });
得出的結果:
1 09-20 15:33:12.208 7352-7352/com.example.huangjialin.md5test I/huangjialin: md5_123456abc算出的MD5值是: df10ef8509dc176d733d59549e7dbfaf 2 3 09-20 15:33:12.208 7352-7352/com.example.huangjialin.md5test I/huangjialin: md5_huangjialin算出的MD5值是: 08e768954478c8669619d7d087db0070
這裏說一句題外話:Log輸出日誌有不少種如Log.i();Log.d()等等,可是如今有些手機廠商直接就把等級較低的日誌給屏蔽掉,因此有些日誌輸出在有些手機能夠看到,有些手機沒有看到。解決辦法就是換輸出等級較高的就OK了。
RSA
RSA是如今比較流行的一種非對稱加密的,它須要一對密鑰(公鑰和私鑰)公鑰進行加密,私鑰進行解密。
RSA的加密原理
一、隨機選擇兩個大的質數P和Q,P不等於Q,計算出結果:N = P*Q;
二、選擇一個大於1,小於N的天然數E,E必須和(P-1)*(Q-1)互素。
三、用公式計算出D:D*E = mod(P-1)*(Q-1)
四、銷燬P和Q
最終獲得的N,E就是公鑰,D就是私鑰了。
RSA加解密步驟
一、甲方生成密鑰對(公鑰和私鑰,公鑰用來加密數據,私鑰本身保留,用來解密數據)
二、甲方使用私鑰加密數據,而後用私鑰對加密後的數據簽名,並把這些放送給乙方,乙方使用公鑰,簽名來驗證帶解密數據是否有效,若是有效就使用公鑰對數據進行解密
三、乙方使用公鑰加密數據,向甲方發送通過加密後的數據,甲方或者加密數據後,就能夠經過私鑰進行解密了。
RSA使用場景
項目中一些敏感的數據,好比身份證號,銀行卡,等相關信息可經過加密後在傳給服務器,服務器使用私鑰進行解密。
RSA密鑰對生成
RSA的密鑰對生成方式有兩種
1 /* 2 初始化KeyPairGenerator類,並獲取到公鑰和私鑰 3 */ 4 byte[] publicKeyByte; 5 byte[] prvateKtyByte; 6 7 public void getKey() { 8 try { 9 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(「RSA」);//KeyPairGenerator類是java專門提供生成密鑰對的一個類。 10 keyPairGenerator.initialize(1024); //設置密鑰對的大小 11 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 12 PrivateKey privateKey = keyPair.getPrivate();//獲取私鑰 13 PublicKey publicKey = keyPair.getPublic();//獲取公鑰 14 prvateKtyByte = privateKey.getEncoded();//私鑰對應的字節數組 15 publicKeyByte = publicKey.getEncoded(); //公鑰對應的字節數組 16 17 } catch (NoSuchAlgorithmException e) { 18 e.printStackTrace(); 19 } 20 }
固然上面這種生成密鑰對的方式,基本不多會在項目中使用使用,用得比較多的仍是第二中方式。
第二種是經過OpenSSl工具生成密鑰對
這種生成密鑰對的方式須要安裝OpenSSl。這裏就不說具體怎麼安裝了。這裏簡單的說一下生成密鑰對所須要的一些命令
使用命令生成私鑰:
1 genrsa -out rsa_private_key.pem 1024
這條命令是讓openssl隨機生成一份私鑰,長度爲1024
使用命令生成公鑰:
1 rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
命令成功之後,就會在openSSL下的bin目錄下生成公鑰和私鑰,而後就能夠進行加密和解密了。
加密
1 /** 2 * 加密 3 */ 4 5 6 @RequiresApi(api = Build.VERSION_CODES.O) 7 public byte[] encryption(String content) { 8 byte[] result = null; 9 try { 10 Cipher cipher = Cipher.getInstance("RSA"); 11 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyByte); 12 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 13 PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); 14 cipher.init(Cipher.ENCRYPT_MODE, publicKey); 15 result = cipher.doFinal(content.getBytes()); 16 Log.i("huangjialin", "----> " + Base64.getEncoder().encodeToString(result)); 17 } catch (NoSuchAlgorithmException e) { 18 e.printStackTrace(); 19 } catch (NoSuchPaddingException e) { 20 e.printStackTrace(); 21 } catch (InvalidKeySpecException e) { 22 e.printStackTrace(); 23 } catch (InvalidKeyException e) { 24 e.printStackTrace(); 25 } catch (BadPaddingException e) { 26 e.printStackTrace(); 27 } catch (IllegalBlockSizeException e) { 28 e.printStackTrace(); 29 } 30 return result; 31 }
解密
1 /** 2 * 解密 3 */ 4 5 @RequiresApi(api = Build.VERSION_CODES.O) 6 7 public void decryption() { 8 9 Cipher cipher = null; 10 try { 11 cipher = Cipher.getInstance("RSA"); 12 //私鑰須要經過PKCS8EncodedKeySpec來讀取 13 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(prvateKtyByte); 14 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 15 //生成私鑰 16 PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 17 cipher.init(Cipher.DECRYPT_MODE, privateKey); 18 //String content = "123456"; 19 byte[] input = encryption("123456"); 20 byte[] result = cipher.doFinal(input); 21 Log.i("huangjialin", "--解密--> " + new String(result)); 22 //Assert.assertTrue(content.equals(new String(result))); 23 24 25 } catch (NoSuchAlgorithmException e) { 26 e.printStackTrace(); 27 } catch (NoSuchPaddingException e) { 28 e.printStackTrace(); 29 } catch (BadPaddingException e) { 30 e.printStackTrace(); 31 } catch (IllegalBlockSizeException e) { 32 e.printStackTrace(); 33 } catch (InvalidKeyException e) { 34 e.printStackTrace(); 35 } catch (InvalidKeySpecException e) { 36 e.printStackTrace(); 37 } 38 39 40 }
固然上面的代碼是我寫測試用的,真正項目中,還得封裝好,把它弄成工具類,進行調用。
AES
AES是一個對稱加密,也就是說使用AES進行加密和解密,他們使用的密鑰都是同樣的。AES加密算法是密碼學中的高級加密標準,又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析並使用。同時AES他的算法加密強度大,執行效率很高。
AES使用場景
一、因爲AES是對稱加密,加解密都是使用同一個密鑰,因此說在項目中一些敏感的數據須要保存到本地。能夠先同AES的密鑰進行加密,須要用的使用,將數據取出來再進行解密。
二、能夠進行對一些敏感數據進行加密,而後在傳遞給服務器。
AES使用
在Android7.0以前能夠這樣獲取到密鑰
1 private SecretKey generateKey(String seed) throws Exception { 2 // 獲取祕鑰生成器 3 KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); 4 // 經過種子初始化 5 SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "Crypto"); 6 7 secureRandom.setSeed(seed.getBytes("UTF-8")); 8 keyGenerator.init(128, secureRandom); 9 // 生成祕鑰並返回 10 return keyGenerator.generateKey(); 11 }
可是在Android7.0以後就不支持了,移除了Crypto。固然也這種獲取密鑰方式在7.0以後Google也給出瞭解決方案,可是官方並不建議這樣來獲取。具體的能夠看這裏。https://android-developers.googleblog.com/2016/06/security-crypto-provider-deprecated-in.html
官方給出的是另外一種方式,並不須要獲取密鑰,而是定義密碼的形式。
1 package com.example.huangjialin.md5test; 2 3 import android.os.Bundle; 4 import android.support.v7.app.AppCompatActivity; 5 import android.util.Base64; 6 import android.util.Log; 7 import android.view.View; 8 import android.widget.Button; 9 import android.widget.EditText; 10 import android.widget.TextView; 11 12 import javax.crypto.Cipher; 13 import javax.crypto.SecretKey; 14 import javax.crypto.spec.SecretKeySpec; 15 16 public class MainActivity extends AppCompatActivity { 17 private EditText edittext; 18 private Button button, jiami, jiemi; 19 private TextView textView; 20 private SecretKey secretKey; 21 private byte[] bytes; 22 private String content = "huangjialin,我是要加密的數據"; 23 String password = "huangji黃家磷"; 24 25 @Override 26 protected void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.activity_main); 29 30 edittext = findViewById(R.id.edittext); 31 button = findViewById(R.id.button); 32 textView = findViewById(R.id.textview); 33 jiami = findViewById(R.id.jiami); 34 jiemi = findViewById(R.id.jiemi); 35 36 Log.i("huagjialin", "--加密的數據-- > " + content); 37 38 /** 39 * 獲取密鑰 40 */ 41 /* button.setOnClickListener(new View.OnClickListener() { 42 @Override 43 public void onClick(View v) { 44 try { 45 secretKey = generateKey("huangjiain"); 46 } catch (Exception e) { 47 e.printStackTrace(); 48 } 49 50 } 51 });*/ 52 53 54 /** 55 * 加密 56 */ 57 58 jiami.setOnClickListener(new View.OnClickListener() { 59 @Override 60 public void onClick(View v) { 61 try { 62 bytes = encrypt(content, password); 63 String str = new String(bytes); 64 Log.i("huagjialin", "--加密後的數據-- > " + Base64.decode(str,Base64.DEFAULT)); 65 } catch (Exception e) { 66 e.printStackTrace(); 67 } 68 69 } 70 }); 71 72 /** 73 * 解密 74 */ 75 76 jiemi.setOnClickListener(new View.OnClickListener() { 77 @Override 78 public void onClick(View v) { 79 try { 80 byte[] by = decrypt(bytes, password); 81 String string = new String(by); 82 Log.i("huagjialin", "--解密後的數據-- > " + string); 83 } catch (Exception e) { 84 e.printStackTrace(); 85 } 86 } 87 }); 88 89 90 } 91 92 93 94 95 96 97 /** 98 * 另外一種加密形式 99 */ 100 private byte[] encrypt(String content, String password) throws Exception { 101 // 建立AES祕鑰 102 SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES/CBC/PKCS5PADDING"); 103 // 建立密碼器 104 Cipher cipher = Cipher.getInstance("AES"); 105 // 初始化加密器 106 cipher.init(Cipher.ENCRYPT_MODE, key); 107 // 加密 108 return cipher.doFinal(content.getBytes("UTF-8")); 109 } 110 111 112 /** 113 * 解密 114 */ 115 private byte[] decrypt(byte[] content, String password) throws Exception { 116 // 建立AES祕鑰 117 SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES/CBC/PKCS5PADDING"); 118 // 建立密碼器 119 Cipher cipher = Cipher.getInstance("AES"); 120 // 初始化解密器 121 cipher.init(Cipher.DECRYPT_MODE, key); 122 // 解密 123 return cipher.doFinal(content); 124 } 125 126 }
1 09-20 21:12:36.394 15933-15933/com.example.huangjialin.md5test I/huagjialin: --加密的數據-- > huangjialin,我是要加密的數據 2 09-20 21:12:39.561 15933-15933/com.example.huangjialin.md5test I/huagjialin: --加密後的數據-- > [B@d62495e 3 09-20 21:12:41.829 15933-15933/com.example.huangjialin.md5test I/huagjialin: --解密後的數據-- > huangjialin,我是要加密的數據
以上就是咱們比較經常使用的幾種加密的一些內容。好了,這篇內容就到這,文中若是錯誤,麻煩大神指教,共同進步