Android 指紋識(shí)別詳解及實(shí)現(xiàn)方法
最近項(xiàng)目需要使用到指紋識(shí)別的功能,查閱了相關(guān)資料后,整理成此文。
指紋識(shí)別是在Android 6.0之后新增的功能,因此在使用的時(shí)候需要先判斷用戶手機(jī)的系統(tǒng)版本是否支持指紋識(shí)別。另外,實(shí)際開(kāi)發(fā)場(chǎng)景中,使用指紋的主要場(chǎng)景有兩種:
純本地使用。即用戶在本地完成指紋識(shí)別后,不需要將指紋的相關(guān)信息給后臺(tái)。
與后臺(tái)交互。用戶在本地完成指紋識(shí)別后,需要將指紋相關(guān)的信息傳給后臺(tái)。
由于使用指紋識(shí)別功能需要一個(gè)加密對(duì)象(CryptoObject)該對(duì)象一般是由對(duì)稱加密或者非對(duì)稱加密獲得。上述兩種開(kāi)發(fā)場(chǎng)景的實(shí)現(xiàn)大同小異,主要區(qū)別在于加密過(guò)程中密鑰的創(chuàng)建和使用,一般來(lái)說(shuō),純本地的使用指紋識(shí)別功能,只需要對(duì)稱加密即可;而與后臺(tái)交互則需要使用非對(duì)稱加密:將私鑰用于本地指紋識(shí)別,識(shí)別成功后將加密信息傳給后臺(tái),后臺(tái)開(kāi)發(fā)人員用公鑰解密,以獲得用戶信息。
下面先簡(jiǎn)單介紹一下對(duì)稱加密和非對(duì)稱加密的相關(guān)概念,然后對(duì)兩種開(kāi)發(fā)方式的實(shí)現(xiàn)分別進(jìn)行講解。
對(duì)稱加密、非對(duì)稱加密和簽名
在正式使用指紋識(shí)別功能之前,有必要先了解一下對(duì)稱加密和非對(duì)稱加密的相關(guān)內(nèi)容。
對(duì)稱加密:所謂對(duì)稱,就是采用這種加密方法的雙方使用方式用同樣的密鑰進(jìn)行加密和解密。密鑰是控制加密及解密過(guò)程的指令。算法是一組規(guī)則,規(guī)定如何進(jìn)行加密和解密。因此加密的安全性不僅取決于加密算法本身,密鑰管理的安全性更是重要。因?yàn)榧用芎徒饷芏际褂猛粋€(gè)密鑰,如何把密鑰安全地傳遞到解密者手上就成了必須要解決的問(wèn)題。
非對(duì)稱加密:非對(duì)稱加密算法需要兩個(gè)密鑰:公開(kāi)密鑰(publickey)和私有密鑰(privatekey)。公開(kāi)密鑰與私有密鑰是一對(duì),如果用公開(kāi)密鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私有密鑰才能解密;如果用私有密鑰對(duì)數(shù)據(jù)進(jìn)行加密,那么只有用對(duì)應(yīng)的公開(kāi)密鑰才能解密。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱加密算法。 非對(duì)稱加密算法實(shí)現(xiàn)機(jī)密信息交換的基本過(guò)程是:甲方生成一對(duì)密鑰并將其中的一把作為公用密鑰向其它方公開(kāi);得到該公用密鑰的乙方使用該密鑰對(duì)機(jī)密信息進(jìn)行加密后再發(fā)送給甲方;甲方再用自己保存的另一把專用密鑰對(duì)加密后的信息進(jìn)行解密。
簽名:在信息的后面再加上一段內(nèi)容,可以證明信息沒(méi)有被修改過(guò)。一般是對(duì)信息做一個(gè)hash計(jì)算得到一個(gè)hash值,注意,這個(gè)過(guò)程是不可逆的,也就是說(shuō)無(wú)法通過(guò)hash值得出原來(lái)的信息內(nèi)容。在把信息發(fā)送出去時(shí),把這個(gè)hash值加密后做為一個(gè)簽名和信息一起發(fā)出去。
由以上內(nèi)容可以了解到,對(duì)稱加密和非對(duì)稱加密的特點(diǎn)如下:
對(duì)稱加密的優(yōu)點(diǎn)是速度快,適合于本地?cái)?shù)據(jù)和本地?cái)?shù)據(jù)庫(kù)的加密,安全性不如非對(duì)稱加密。常見(jiàn)的對(duì)稱加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6。
非對(duì)稱加密的安全性比較高,適合對(duì)需要網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)進(jìn)行加密,速度不如對(duì)稱加密。非對(duì)稱加密應(yīng)用于SSH, HTTPS, TLS,電子證書(shū),電子簽名,電子身份證等等
指紋識(shí)別的對(duì)稱加密實(shí)現(xiàn)
使用指紋識(shí)別的對(duì)稱加密功能的主要流程如下:
- 使用 KeyGenerator 創(chuàng)建一個(gè)對(duì)稱密鑰,存放在 KeyStore 里。
- 設(shè)置 KeyGenParameterSpec.Builder.setUserAuthenticationRequired() 為true,
- 使用創(chuàng)建好的對(duì)稱密鑰初始化一個(gè)Cipher對(duì)象,并用該對(duì)象調(diào)用 FingerprintManager.authenticate() 方法啟動(dòng)指紋傳感器并開(kāi)始監(jiān)聽(tīng)。
- 重寫(xiě) FingerprintManager.AuthenticationCallback 的幾個(gè)回調(diào)方法,以處理指紋識(shí)別成功(onAuthenticationSucceeded())、失?。╫nAuthenticationFailed() 和 onAuthenticationError())等情況。
創(chuàng)建密鑰
創(chuàng)建密鑰要涉及到兩個(gè)類(lèi):KeyStore 和 KeyGenerator。
KeyStore 是用于存儲(chǔ)、獲取密鑰(Key)的容器,獲取 KeyStore的方法如下:
try {
mKeyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException e) {
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
而生成 Key,如果是對(duì)稱加密,就需要 KeyGenerator 類(lèi)。獲取一個(gè) KeyGenerator 對(duì)象比較簡(jiǎn)單,方法如下:
// 對(duì)稱加密, 創(chuàng)建 KeyGenerator 對(duì)象
try {
mKeyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
獲得 KeyGenerator 對(duì)象后,就可以生成一個(gè) Key 了:
try {
keyStore.load(null);
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(defaultKeyName,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setInvalidatedByBiometricEnrollment(true);
}
keyGenerator.init(builder.build());
keyGenerator.generateKey();
} catch (CertificateException | NoSuchAlgorithmException | IOException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
關(guān)于 KeyStrore 和 KeyGenerator 的相關(guān)介紹,推薦閱讀:Android KeyStore + FingerprintManager 存儲(chǔ)密碼
創(chuàng)建并初始化 Cipher 對(duì)象
Cipher 對(duì)象是一個(gè)按照一定的加密規(guī)則,將數(shù)據(jù)進(jìn)行加密后的一個(gè)對(duì)象。調(diào)用指紋識(shí)別功能需要使用到這個(gè)對(duì)象。創(chuàng)建 Cipher 對(duì)象很簡(jiǎn)單,如同下面代碼那樣:
Cipher defaultCipher;
try {
defaultCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("創(chuàng)建Cipher對(duì)象失敗", e);
}
然后使用剛才創(chuàng)建好的密鑰,初始化 Cipher 對(duì)象:
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(keyName, null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {
throw new RuntimeException("初始化 cipher 失敗", e);
}
使用指紋識(shí)別功能
真正到了使用指紋識(shí)別功能的時(shí)候,你會(huì)發(fā)現(xiàn)其實(shí)很簡(jiǎn)單,只是調(diào)用 FingerprintManager 類(lèi)的的方法authenticate()而已,然后系統(tǒng)會(huì)有相應(yīng)的回調(diào)反饋給我們,該方法如下:
public void authenticate(CryptoObject crypto, CancellationSignal cancel, int flags, AuthenticationCallback callback, Handler handler)
該方法的幾個(gè)參數(shù)解釋如下:
- 第一個(gè)參數(shù)是一個(gè)加密對(duì)象。還記得之前我們大費(fèi)周章地創(chuàng)建和初始化的Cipher對(duì)象嗎?這里的 CryptoObject 對(duì)象就是使用 Cipher 對(duì)象創(chuàng)建創(chuàng)建出來(lái)的:new FingerprintManager.CryptoObject(cipher)。
- 第二個(gè)參數(shù)是一個(gè) CancellationSignal 對(duì)象,該對(duì)象提供了取消操作的能力。創(chuàng)建該對(duì)象也很簡(jiǎn)單,使用 new CancellationSignal() 就可以了。
- 第三個(gè)參數(shù)是一個(gè)標(biāo)志,默認(rèn)為0。
- 第四個(gè)參數(shù)是 AuthenticationCallback 對(duì)象,它本身是 FingerprintManager 類(lèi)里面的一個(gè)抽象類(lèi)。該類(lèi)提供了指紋識(shí)別的幾個(gè)回調(diào)方法,包括指紋識(shí)別成功、失敗等。需要我們重寫(xiě)。
- 最后一個(gè) Handler,可以用于處理回調(diào)事件,可以傳null。
完成指紋識(shí)別后,還要記得將 AuthenticationCallback 關(guān)閉掉:
public void stopListening() {
if (cancellationSignal != null) {
selfCancelled = true;
cancellationSignal.cancel();
cancellationSignal = null;
}
}
重寫(xiě)回調(diào)方法
調(diào)用了 authenticate() 方法后,系統(tǒng)就會(huì)啟動(dòng)指紋傳感器,并開(kāi)始掃描。這時(shí)候根據(jù)掃描結(jié)果,會(huì)通過(guò)
FingerprintManager.AuthenticationCallback類(lèi)返回幾個(gè)回調(diào)方法:
// 成功 onAuthenticationSucceeded() // 失敗 onAuthenticationFaile() // 錯(cuò)誤 onAuthenticationError()
一般我們需要重寫(xiě)這幾個(gè)方法,以實(shí)現(xiàn)我們的功能。關(guān)于onAuthenticationFaile()和onAuthenticationError()的區(qū)別,后面會(huì)講到。
指紋識(shí)別的非對(duì)稱加密實(shí)現(xiàn)
其實(shí)流程和上面的流程差不多:
- 使用 KeyPairGenerator 創(chuàng)建一個(gè)非對(duì)稱密鑰。
- 使用創(chuàng)建好的私鑰進(jìn)行簽名,使用該簽名創(chuàng)建一個(gè)加密對(duì)象,并將該對(duì)象作為 FingerprintManager.authenticate() 方法的一個(gè)參數(shù),啟動(dòng)指紋傳感器并開(kāi)始監(jiān)聽(tīng)。
- 重寫(xiě) FingerprintManager.AuthenticationCallback 類(lèi)的幾個(gè)回調(diào)方法,以處理指紋識(shí)別成功(onAuthenticationSucceeded())、失?。╫nAuthenticationFailed() 和 onAuthenticationError())等情況。
可以看見(jiàn),指紋識(shí)別的非對(duì)稱加密方式和對(duì)稱加密方式的實(shí)現(xiàn)流程是差不多的,它們之間最明顯的差別是在于密鑰的生成與使用。
創(chuàng)建密鑰
這里要使用 KeyPairGenerator 來(lái)創(chuàng)建一組非對(duì)稱密鑰,首先是獲取 KeyPairGenerator 對(duì)象:
// 非對(duì)稱加密,創(chuàng)建 KeyPairGenerator 對(duì)象
try {
mKeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("Failed to get an instance of KeyPairGenerator", e);
}
得到了 KeyPairGenerator 對(duì)象后,就可以創(chuàng)建 KeyPair(密鑰對(duì))了:
try {
// Set the alias of the entry in Android KeyStore where the key will appear
// and the constrains (purposes) in the constructor of the Builder
mKeyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
// Require the user to authenticate with a fingerprint to authorize
// every use of the private key
.setUserAuthenticationRequired(true)
.build());
mKeyPairGenerator.generateKeyPair();
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
簽名
指紋識(shí)別的對(duì)稱加密實(shí)現(xiàn)中使用了Cipher對(duì)象來(lái)創(chuàng)建CryptoObject對(duì)象,而在這里,我們將會(huì)使用私鑰進(jìn)行簽名,用簽名對(duì)象來(lái)創(chuàng)建CryptoObject對(duì)象:
// 使用私鑰簽名
try {
mKeyStore.load(null);
PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
mSignature.initSign(key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
return false;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
}
同樣的,調(diào)用new FingerprintManager.CryptoObject(mSignature)方法創(chuàng)建一個(gè)CryptoObject對(duì)象。
調(diào)用指紋識(shí)別方法
這里的使用方法和前面“指紋識(shí)別的對(duì)稱加密實(shí)現(xiàn)”中的調(diào)用方法是一樣的,都是調(diào)用FingerprintManager.authenticate()方法。這里就不再敘述。
監(jiān)聽(tīng)回調(diào)
監(jiān)聽(tīng)回調(diào)也和之前的類(lèi)似,唯一不同的是,我們?cè)谧R(shí)別成功后需要和后臺(tái)進(jìn)行交互,也就是onAuthenticationSucceeded()中處理的邏輯不一樣。
實(shí)際應(yīng)用中的注意事項(xiàng)
判斷用戶是否可以使用指紋識(shí)別功能
一般來(lái)說(shuō),為了增加安全性,要求用戶在手機(jī)的“設(shè)置”中開(kāi)啟了密碼鎖屏功能。當(dāng)然,使用指紋解鎖的前提是至少錄入了一個(gè)指紋。
// 如果沒(méi)有設(shè)置密碼鎖屏,則不能使用指紋識(shí)別
if (!keyguardManager.isKeyguardSecure()) {
Toast.makeText(this, "請(qǐng)?jiān)谠O(shè)置界面開(kāi)啟密碼鎖屏功能",
Toast.LENGTH_LONG).show();
}
// 如果沒(méi)有錄入指紋,則不能使用指紋識(shí)別
if (!fingerprintManager.hasEnrolledFingerprints()) {
Toast.makeText(this, "您還沒(méi)有錄入指紋, 請(qǐng)?jiān)谠O(shè)置界面錄入至少一個(gè)指紋",
Toast.LENGTH_LONG).show();
}
這里用到了兩個(gè)類(lèi):KeyguardManager 和 FingerprintManager,前者是屏幕保護(hù)的相關(guān)類(lèi)。后者是指紋識(shí)別的核心類(lèi)。
關(guān)于指紋識(shí)別回調(diào)方法
前面說(shuō)到AuthenticationCallback類(lèi)里面的幾個(gè)回調(diào)方法,其中有三個(gè)是我們開(kāi)發(fā)中需要用到的:
onAuthenticationError() onAuthenticationSucceeded() onAuthenticationFailed()
關(guān)于這三個(gè)回調(diào)方法,有幾點(diǎn)需要注意的:
1.當(dāng)指紋識(shí)別失敗后,會(huì)調(diào)用onAuthenticationFailed()方法,這時(shí)候指紋傳感器并沒(méi)有關(guān)閉,系統(tǒng)給我們提供了5次重試機(jī)會(huì),也就是說(shuō),連續(xù)調(diào)用了5次onAuthenticationFailed()方法后,會(huì)調(diào)用onAuthenticationError()方法。
2.當(dāng)系統(tǒng)調(diào)用了onAuthenticationError()和onAuthenticationSucceeded()后,傳感器會(huì)關(guān)閉,只有我們重新授權(quán),再次調(diào)用authenticate()方法后才能繼續(xù)使用指紋識(shí)別功能。
3.當(dāng)系統(tǒng)回調(diào)了onAuthenticationError()方法關(guān)閉傳感器后,這種情況下再次調(diào)用authenticate()會(huì)有一段時(shí)間的禁用期,也就是說(shuō)這段時(shí)間里是無(wú)法再次使用指紋識(shí)別的。當(dāng)然,具體的禁用時(shí)間由手機(jī)廠商的系統(tǒng)不同而有略微差別,有的是1分鐘,有的是30秒等等。而且,由于手機(jī)廠商的系統(tǒng)區(qū)別,有些系統(tǒng)上調(diào)用了onAuthenticationError()后,在禁用時(shí)間內(nèi),其他APP里面的指紋識(shí)別功能也無(wú)法使用,甚至系統(tǒng)的指紋解鎖功能也無(wú)法使用。而有的系統(tǒng)上,在禁用時(shí)間內(nèi)調(diào)用其他APP的指紋解鎖功能,或者系統(tǒng)的指紋解鎖功能,就能立即重置指紋識(shí)別功能。
示例代碼
最后, Android Sample 里面關(guān)于指紋的示例代碼地址如下:
對(duì)稱加密方式:android-FingerprintDialog。
非對(duì)稱加密方式:android-AsymmetricFingerprintDialog
參考鏈接:New in Android Samples: Authenticating to remote servers using the Fingerprint API
以上就是對(duì)Android 開(kāi)發(fā)指紋識(shí)別的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android實(shí)現(xiàn)九宮格手勢(shì)解鎖
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)九宮格手勢(shì)解鎖的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Android實(shí)現(xiàn)圖片循環(huán)播放的實(shí)例方法
2013-05-05
Android中點(diǎn)擊隱藏軟鍵盤(pán)最佳方法
本文介紹了Android中點(diǎn)擊隱藏軟鍵盤(pán)最佳方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01
Android設(shè)備藍(lán)牙連接掃描槍獲取掃描內(nèi)容
這篇文章主要為大家詳細(xì)介紹了Android設(shè)備藍(lán)牙連接掃描槍獲取掃描內(nèi)容,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Android自定義有限制區(qū)域圖例角度自識(shí)別涂鴉工具類(lèi)
這篇文章主要為大家介紹了Android自定義有限制區(qū)域圖例角度自識(shí)別涂鴉工具類(lèi),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Android編程實(shí)現(xiàn)應(yīng)用程序開(kāi)機(jī)自啟動(dòng)的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)應(yīng)用程序開(kāi)機(jī)自啟動(dòng)的方法,涉及Android權(quán)限控制及廣播操作相關(guān)技巧,需要的朋友可以參考下2017-02-02
Android 圖片保存到相冊(cè)不顯示的解決方案(兼容Android 10及更高版本)
這篇文章主要介紹了Android 圖片保存到系統(tǒng)相冊(cè)不顯示的解決方案,幫助大家更好的理解和學(xué)習(xí)使用Android開(kāi)發(fā),感興趣的朋友可以了解下2021-04-04
Android開(kāi)發(fā)中的簡(jiǎn)單設(shè)置技巧集錦
這篇文章主要介紹了Android開(kāi)發(fā)中的簡(jiǎn)單設(shè)置技巧,較為詳細(xì)的匯總了Android針對(duì)壁紙、語(yǔ)言、音量、錄音等多種設(shè)置的方法,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2016-06-06

