旅游三級分銷網(wǎng)站google關(guān)鍵詞優(yōu)化排名
在我們App開發(fā)過程中,可能會涉及到一些敏感和安全數(shù)據(jù)需要加密的情況,比如登錄token的存儲。我們往往會使用一些加密算法將這些敏感數(shù)據(jù)加密之后再保存起來,需要取出來的時候再進(jìn)行解密。
此時就會有一個問題:用于加解密的Key該如何存儲?
- 如果把Key和加密后的數(shù)據(jù)存到一起,那有一定的安全風(fēng)險。
- 對Key再進(jìn)行一次加密,這就陷入了死循環(huán)。
為了保證安全性,Android提供了KeyStore
系統(tǒng)來保存Key,本文就淺探一下KeyStore
及其使用方法。
一、什么是KeyStore?如何保證安全性?
1、什么是KeyStore?
先來看看官方對他的定義:
This class represents a storage facility for cryptographic keys and certificates.
這個類代表加密密鑰和證書的存儲設(shè)施
定義其實很簡單,他就是用來保存加解密的Key和證書的。
2、如何保證安全性?
安全性保護(hù)措施在官方文檔里有寫(Android 密鑰庫系統(tǒng) | Android 開發(fā)者 | Android Developers (google.cn)), 我就按自己的理解總結(jié)一下:
- Key是保存在手機(jī)系統(tǒng)里的,應(yīng)用進(jìn)程在獲取Key的時候是通過系統(tǒng)進(jìn)程獲取到內(nèi)存里的。也就是說只能在本應(yīng)用進(jìn)程里才能拿到Key,想要把Key提取出來是不可能的。
KeyStore
還可以指定密鑰的授權(quán)使用方式(比如用戶安全鎖驗證),可保證必須在授權(quán)的情況下才能獲取到Key。
總的來說就是使用者只能在應(yīng)用程序運(yùn)行時使用KeyStore
里存放的Key,除非攻擊者拿到源碼打斷點(diǎn)調(diào)試,否則無法知道Key到底是什么。這樣就保證了存儲Key的安全性。
二、KeyStore的使用
KeyStore
支持的加密算法有很多,其中對部分算法有API Level的要求,具體可以查看Android 密鑰庫系統(tǒng) | Android 開發(fā)者 | Android Developers (google.cn)
本文就以AES加密算法為例,簡單說明一下KeyStore
的使用方式。注意,本文涉及到的代碼需要minSdk>=23.
先簡單實現(xiàn)一下AES算法的加解密
1、數(shù)據(jù)加密
object AESUtil {private const val IV_BLOCK_SIZE = 16fun encryptAES(encryptBytes: ByteArray, encryptKey: SecretKey): ByteArray?{try {//創(chuàng)建密碼器val cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING")//用密鑰初始化Cipher對象cipher.init(Cipher.ENCRYPT_MODE, encryptKey)val final = cipher.doFinal(encryptBytes)// iv占前16位,加密后的數(shù)據(jù)占后面return cipher.iv + final} catch (e: NoSuchPaddingException) {e.printStackTrace()} catch (e: NoSuchAlgorithmException) {e.printStackTrace()} catch (e: InvalidAlgorithmParameterException) {e.printStackTrace()} catch (e: InvalidKeyException) {e.printStackTrace()} catch (e: BadPaddingException) {e.printStackTrace()} catch (e: IllegalBlockSizeException) {e.printStackTrace()}return null}fun decryptAES(decryptBytes: ByteArray, decryptKey: SecretKey): ByteArray? {try {// 先取出IVval iv = decryptBytes.copyOfRange(0, IV_BLOCK_SIZE)// 取出加密后的數(shù)據(jù)val decryptData = decryptBytes.copyOfRange(IV_BLOCK_SIZE, decryptBytes.size)val cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING")cipher.init(Cipher.DECRYPT_MODE, decryptKey, IvParameterSpec(iv))return cipher.doFinal(decryptData)} catch (e: NoSuchPaddingException) {e.printStackTrace()} catch (e: NoSuchAlgorithmException) {e.printStackTrace()} catch (e: InvalidAlgorithmParameterException) {e.printStackTrace()} catch (e: InvalidKeyException) {e.printStackTrace()} catch (e: BadPaddingException) {e.printStackTrace()} catch (e: IllegalBlockSizeException) {e