title: BadPaddingException when trying to decrypt Fingerprint API cypher
body: <p>In my app, I save an encrypted version of the user's access code when they scan their finger in the initial setup [fingerprint enrollment]. When the user tries to unlock the app at a later time, I will attempt to decrypt this access code using the Fingerprint API [fingerprint verification].</p>
  
  <p>However, <code>Cipher.doFinal</code> throws the following exception on decryption:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>The fingerprint scanner is displayed in a <code>DialogFragment</code>. The following functions are always called in order from the constructor, regardless of whether the fingerprint is being enrolled or verified.</p>
  
  <p>Initialize the keystore:</p>
  
  <pre><code>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;
      }
  }
  </code></pre>
  
  <p>Create a key:</p>
  
  <pre><code>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;
          }
      }
  }
  </code></pre>
  
  <p>Create cipher object:</p>
  
  <pre><code>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;
      }
  }
  </code></pre>
  
  <p>When the the fingerprint scanner API successfully authenticates the user, the following code is called in sequence:</p>
  
  <pre><code>@Nullable Cipher getCipher(@NonNull final FingerprintStore ivStore) {
      if (mKeyStore != null &amp;&amp; mKeyGenerator != null &amp;&amp; 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;
  }
  </code></pre>
  
  <p>And, using the instance of Cipher just returned from the previous call:</p>
  
  <pre><code>@Nullable byte[] encryptOrDecrypt(@NonNull Cipher cipher, @NonNull byte[] subject) {
      try {
          return cipher.doFinal(subject);
      } catch (BadPaddingException | IllegalBlockSizeException e) {
          e.printStackTrace();
          return null;
      }
  }
  </code></pre>
  
  <p>This call to <code>doFinal</code> works fine when encrypting the data, but throws the exception on decryption. I have inspected the <code>byte[]</code>'s of the both the initialization vector and the encrypted data and have found that they are being stored to disk (Base64) and read back into memory correctly.</p>