Android 免密支付+Keystore體系

首先我們要實現這個功能需要確認幾個問題

1.如何創建一個Keystore並保證其唯一性
2.如何設置KeyProtection
3.如何把密鑰也就是密碼放到安卓Keystore裏面
4.如何通過指紋獲取到Keystore裏面存儲的密碼
5.當指紋變更之後如何失效
6. secret key的作用,對稱加密
7.指紋驗證通過之後如何獲取到存儲在Android Keystore裏面密文
這個問題可以分成兩個問題看待,第一個問題是安卓的Keystore體系,第二個是生物識別

參考文章:
Android指紋識別,看這一篇就夠了
Android 保存私密信息-強大的 keyStore
Android KeyStore + FingerprintManager 存儲密碼

Keystore體系

創建一個密鑰(SecretKey)

安卓內部是提供一套Keystore體系用於用戶加密的,我們可以通過

 KeyStore androidKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);//獲取到Android的Keystore類

我們所獲取的androidKeyStore 就是安卓系統的keystore

“AndroidKeyStore”:這裏要先區分下AndroidKeyStore和Android
KeyStore,雖然這兩個一樣,但是後者中間多了個空格,意義是不一樣的,前者是子集,後者是父集,後者包含前者。而AndroidKeyStore主要是用來存儲一些密鑰key的,存進該處的key可以爲其設置KeyProtection,例如只能通過用戶驗證才能取出key使用等。這些key是存在系統裏的,不是在app的目錄下,並且每個app不能訪問其他app的key,如果app1創建了key1,並且存儲的時候命名爲temp,app2去通過temp去訪問key,是獲取不到的!!
KeyStore.getDefaultType():該函數返回的是一個字符串,在java下,返回的是JKS,在Android下,返回的是BKS(
生成android使用的BKS證書)。(注:android
系統中使用的證書要求以BKS的庫文件結構保存,通常情況下,我們使用java的keytool只能生成jks的證書庫。讀取key可以通過psw來讀取)。當你使用這個keystore的時候,其文件存放在data(沙盒中)

之後我們需要對這個Keystore做一下初始化參數,我們才能生成一個真正屬於自己的可以加密的系統

 KeyStore androidKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
            androidKeyStore.load(null);
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
            KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
                    KeyProperties.PURPOSE_ENCRYPT |
                            KeyProperties.PURPOSE_DECRYPT)
                                               .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                                               .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                                               //這個設置爲true,表示這個key必須是通過了用戶認證纔可以使用
                                               .setUserAuthenticationRequired(true)
                                               .build();
            keyGenerator.init(spec);
            SecretKey secretKey = keyGenerator.generateKey();

其中 androidKeyStore.load(null);這一點尤其關鍵
load

Added in API level 1 public final void load (InputStream stream,
char[] password) Loads this KeyStore from the given input stream. A password may be given to unlock the keystore (e.g. the
keystore resides on a hardware token device), or to check the
integrity of the keystore data. If a password is not given for
integrity checking, then integrity checking is not performed. In order
to create an empty keystore, or if the keystore cannot be initialized
from a stream, pass null as the stream argument. Note that if this
keystore has already been loaded, it is reinitialized and loaded again
from the given input stream.

Google官方文檔給出的解釋,load(null)是重新創建一個新的Keysotre密鑰庫

加密

接下來我們獲取到了密鑰,然後我們就可以初始化Cipher 對象,這將是實際的加密過程

 Cipher cipher = null;
        cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                                            + KeyProperties.BLOCK_MODE_CBC + "/"
                                            + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher;

我們獲取到的Cipher就是密文
同時這裏我們需要獲取到IV初始化向量,這個東西很重要,對於未來我們做解密的時候獲取密碼的唯一性很重要
引入了一個新的概念:初始向量IV(Initialization Vector)。

IV是做什麼用的呢?它的作用和MD5的“加鹽”有些類似,目的是防止同樣的明文塊始終加密成同樣的密文塊。

  byte[] iv = cipher.getIV();

這個iv需要保存好,是爲了之後解密的時候我們定義其唯一性

解密

 Cipher cipher = null;
        cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                                            + KeyProperties.BLOCK_MODE_CBC + "/"
                                            + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initializeVector);
        cipher.init(Cipher.DECRYPT_MODE,secretKey , ivParameterSpec);

生物識別體系

生物識別,這裏我主要是實現了指紋識別,
在安卓體系下,提供了API23和API28的系統生物識別類,23的FingerprintManager 以及28的BiometricPrompt
至於兩者的區別網上有很多研究,這裏先不管 主要說核心方法

API23

new FingerprintManager.CryptoObject(Cipher cipher);

API28

new BiometricPrompt.CryptoObject(Cipher cipher); //這裏就用到了上文中通過Keystore生成的密文了

我的理解是通過這一步就是實現了 Keystore和生物識別的綁定

之後我們會獲取到 CryptoObject
然後調用 各自的 authenticate()方法就可以獲取系統指紋的回調了

然後我們就可以實現生物識別功能了,關於裏面的參數以及錯誤碼的監聽,網上的攻略比較多,我開頭留的文章就可以找到

總結:這篇文章主要講了如何通過生物識別把密碼保存到Keysotre裏面,然後生物識別通過之後取出密碼的過程,有些地方寫的不是很全,但是總體來說是沒問題的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章