2016-09-13 7 views
4

私のアプリでは、ユーザーのアクセスコードの暗号化されたバージョンが初期設定[指紋登録]で指紋をスキャンして保存します。ユーザーが後でアプリのロックを解除しようとすると、Fingerprint API [指紋認証]を使用してこのアクセスコードを復号しようとします。フィンガープリント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; 
} 

そして、ちょうど前の呼び出しから返された暗号のインスタンスを使用して:

@Nullable byte[] encryptOrDecrypt(@NonNull Cipher cipher, @NonNull byte[] subject) { 
    try { 
     return cipher.doFinal(subject); 
    } catch (BadPaddingException | IllegalBlockSizeException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 

doFinalへのこの呼び出しは、データを暗号化するときに正常に動作しますが、暗号解読に例外がスローされます。私はbyte[]の初期化ベクトルと暗号化されたデータの両方を調べ、それらがディスク(Base64)に格納されており、正しくメモリに読み戻されていることがわかりました。

答えて

4

明らかに私はSecretKeyが登録段階でのみ生成されるべきであるという事実を見落としました。データを解読しようとしたときにcreateKeyが呼び出されたため、doFinalが呼び出される前に新しく生成されたキーで上書きされました。コードは完全に今働いています。

関連する問題