내 앱에서 초기 설정 [지문 등록]에서 손가락을 스캔 할 때 암호화 된 버전의 사용자 액세스 코드를 저장합니다. 사용자가 나중에 앱을 잠금 해제하려고하면 Fingerprint API [지문 인증]을 사용하여이 액세스 코드의 암호를 해독하려고 시도합니다.Fingerprint API 암호 해독을 시도 할 때 BadPaddingException
그러나 Cipher.doFinal
해독에 다음과 같은 예외가 발생 :
javax.crypto.BadPaddingException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:482)
at javax.crypto.Cipher.doFinal(Cipher.java:1502)
(...)
Caused by: android.security.KeyStoreException: Invalid argument
at android.security.KeyStore.getKeyStoreException(KeyStore.java:940)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:473)
... 12 more
지문 스캐너는 DialogFragment
표시된다. 다음 함수는 지문 등록 또는 검증 여부와 관계없이 항상 생성자 순서대로 호출됩니다.
키 스토어 초기화 : 만들기
private void initializeKeystore() {
try {
mKeyStore = KeyStore.getInstance(KEY_STORE_NAME); //AndroidKeyStore
} catch (KeyStoreException e) {
mKeyStore = null;
}
try {
mKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEY_STORE_NAME);
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
mKeyGenerator = null;
}
}
을 핵심 다음 지문 스캐너 API가 성공적으로 사용자를 인증 할 때
private void createCipher() {
try {
mCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
mCipher = null;
}
}
, 다음
private void createKey() {
if (mKeyGenerator != null) {
try {
mKeyStore.load(null);
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
mKeyGenerator.init(builder.build());
mKeyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException |
CertificateException | IOException e) {
mKeyGenerator = null;
}
}
}
이 암호 객체를 생성 코드가 순서대로 호출됩니다.
바로 이전 호출에서 반환 된 암호의 인스턴스를 사용@Nullable Cipher getCipher(@NonNull final FingerprintStore ivStore) {
if (mKeyStore != null && mKeyGenerator != null && mCipher != null) {
try {
mKeyStore.load(null);
SecretKey key = (SecretKey)mKeyStore.getKey(KEY_NAME, null);
switch (mEncryptionMode) {
case MODE_ENCRYPT:
mCipher.init(Cipher.ENCRYPT_MODE, key);
ivStore.writeIv(mCipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV());
break;
case MODE_DECRYPT:
byte[] iv = ivStore.readIv();
mCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
break;
}
return mCipher;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException
| InvalidParameterSpecException | NullPointerException e) {
return null;
}
}
return null;
}
그리고, : doFinal
에
@Nullable byte[] encryptOrDecrypt(@NonNull Cipher cipher, @NonNull byte[] subject) {
try {
return cipher.doFinal(subject);
} catch (BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
return null;
}
}
이 호출은 데이터를 암호화 할 때 잘 작동하지만 암호 해독에 예외가 발생합니다. 난 byte[]
의 초기화 벡터와 암호화 된 데이터를 검사하고 그들이 디스크 (Base64)에 저장되고 다시 메모리에 올바르게 읽혀 있음을 발견했습니다.