利用 Android Keystore 系統,您可以在容器中存儲加密密鑰,從而提高從設備中提取密鑰的難度。在密鑰進入 Keystore 后,可以將它們用于加密操作,而密鑰材料仍不可導出。此外,它提供了密鑰使用的時間和方式限制措施,例如要求進行用戶身份驗證才能使用密鑰,或者限制為只能在某些加密模式中使用。Keystore 系統由KeyChain API 以及在 Android 4.3(API 級別 18)中引入的 Android Keystore 提供程序功能使用。
以上便是google官方對于Android Keystore系統 的一些簡單的介紹,簡單的說Keystore 系統就是可以幫助我們完成一些我們應用中的一些比較私密敏感的信息的加密存儲,以及解密,防止App的一些關鍵信息泄露。我們在實際開發中應該如何使用呢?這里我簡單做個介紹,主要分為三步:第一步,密鑰的創建。第二步,對我們的數據進行加密,然后最后當然就是我們要使用到數據的時候再對加密后的數據進行解密了。
密鑰的創建
在密鑰的創建之前我們先確定我們這里要使用到的加密算法,關于加密算法這一塊有興趣的同學可以自行Google,這里的例子使用到的加密算法為“AES / GCM / NoPadding”。此外我們還需要確定一個別名,這個別名是密鑰在加解密過程中的一個識別連接,相當于我們在傳遞數據中的鍵值對中的鍵這樣的一個作用。密鑰獲取的代碼也不復雜,具體如下:
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException final KeyGenerator keyGenerator = KeyGenerator .getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); keyGenerator.init(new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build()); return keyGenerator.generateKey();
可以看到,我們首先創建得到一個密鑰生成器KeyGenerator 的實例,其中兩個參數的相關說明參看下圖:
然后使用 KeyGenerator 的實例初始化一些相關的配置,如上我們配置了密鑰的別名,以及使用到的相關屬性加密解密,setBlockModes 使我們確信僅指定可用于加密和解密的數據塊模式中,如果使用的任何其他類型的塊模式,它將被拒絕。由于我們使用 “AES / GCM / NoPadding” 轉換算法,我們還告訴KeyGenParameterSpec應該使用的填充類型為NoPadding。至此,我們便完成了通過密鑰生成器生成密鑰的全部過程了。
數據加密
我們加密的實際過程是通過Cipher 類來完成的,還是先看代碼:
byte[] encryptText(final String alias, final String textToEncrypt) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias)); iv = cipher.getIV(); return (encryption = cipher.doFinal(textToEncrypt.getBytes("UTF-8"))); }
可以看到我們首先得到了 Cipher 的實例,并指定了加密的算法為 "AES/GCM/NoPadding" ,然后直接初始化 Cipher 的實例指定為加密模式,并傳入我們的第一步創建的密鑰,這里我們存儲 Cipher 初始化向量(IV),因為我們在解密的時候會用到。最后一步我們便直接調用 Cipher 的 doFinal 完成對數據的加密,doFinal方法返回一個字節數組,它是實際的加密文本,我們直接 Base64 編碼一次就好:
Base64.encodeToString(encryptedText, Base64.DEFAULT)
數據解密
還是老規矩,先上代碼:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv); cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec); return new String(cipher.doFinal(encryptedData), "UTF-8");}
其實加密與解密是一組對稱的操作,解密其實就是加密的一個反向操作。同樣的我們還是需要先獲得 Cipher 的實例,然后我們通過GCMParameterSpec 類來賦予 Cipher 初始化向量的參數,這里簡單的對 GCMParameterSpec 的兩個參數進行說明,簡單的塊密碼模式(例如CBC)通常只需要初始化向量(例如IvParameterSpec),但GCM需要以下參數:
- IV:初始化向量(IV)
- tLen:認證標簽T的長度(以位為單位)
關于 GCMParameterSpec 的更多的信息可以自行查看文檔,這里就不展開討論了。
接下來跟加密一樣的步驟,初始化 Cipher ,這里需要注意的一點便是我們密鑰的獲取:
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException { return ((KeyStore.SecretKeyEntry) keyStore.getEntry(alias, null) }
我們通過我們最初設定的別名識別對應的密鑰,從而通過 keyStore.getEntry(alias, null)).getSecretKey();方法進行獲取得到。
至此我們便完成了通過Android Keystore 系統對APP中的關鍵信息進行加密以及解密的所有過程。
最后
如果你看到了這里,覺得文章寫得不錯就給個贊唄!如果你覺得那里值得改進的,請給我留言。一定會認真查詢,修正不足,謝謝。定期免費分享技術干貨。歡迎大家點贊關注。