Source:
<code>public String decrypt(String value) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, KeyStoreException, CertificateException, NoSuchProviderException, InvalidAlgorithmParameterException, UnrecoverableEntryException, IOException, InvalidKeyException, DigestException, IllegalBlockSizeException, BadPaddingException { Logger.d(TAG, "Starting decryption"); if (StringExtensions.IsNullOrBlank(value)) { throw new IllegalArgumentException("Input is empty or null"); } int encodeVersionLength = value.charAt(0) - 'a'; if (encodeVersionLength <= 0) { throw new IllegalArgumentException("Encode version length is invalid"); } if (!value.substring(1, 1 + encodeVersionLength).equals(ENCODE_VERSION)) { throw new IllegalArgumentException("Encode version does not match"); } <START> final byte[] bytes = Base64.decode(value.substring(1 + ENCODE_VERSION_LENGTH), <END> Base64.DEFAULT); String keyVersionCheck = new String(bytes, 0, KEY_VERSION_BLOB_LENGTH, AuthenticationConstants.ENCODING_UTF8); SecretKey versionKey = getKeyForVersion(keyVersionCheck); SecretKey versionMacKey = getMacKey(versionKey); int ivIndex = bytes.length - DATA_KEY_LENGTH - MAC_LENGTH; int macIndex = bytes.length - MAC_LENGTH; int encryptedLength = ivIndex - KEY_VERSION_BLOB_LENGTH; if (ivIndex < 0 || macIndex < 0 || encryptedLength < 0) { throw new IllegalArgumentException( "Given value is smaller than the IV vector and MAC length"); } Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); Mac mac = Mac.getInstance(MAC_ALGORITHM); mac.init(versionMacKey); mac.update(bytes, 0, macIndex); byte[] macDigest = mac.doFinal(); assertMac(bytes, macIndex, bytes.length, macDigest); cipher.init(Cipher.DECRYPT_MODE, versionKey, new IvParameterSpec(bytes, ivIndex, DATA_KEY_LENGTH)); String decrypted = new String(cipher.doFinal(bytes, KEY_VERSION_BLOB_LENGTH, encryptedLength), AuthenticationConstants.ENCODING_UTF8); Logger.d(TAG, "Finished decryption"); return decrypted; }</code><technical_language>While this work a single version. multi-versions, encodedVersionLength ENCODE_VERSION_LENGTH. avoid a bug</technical_language>

Target:
public String decrypt(String value) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, KeyStoreException, CertificateException, NoSuchProviderException, InvalidAlgorithmParameterException, UnrecoverableEntryException, IOException, InvalidKeyException, DigestException, IllegalBlockSizeException, BadPaddingException { Logger.d(TAG, "Starting decryption"); if (StringExtensions.IsNullOrBlank(value)) { throw new IllegalArgumentException("Input is empty or null"); } int encodeVersionLength = value.charAt(0) - 'a'; if (encodeVersionLength <= 0) { throw new IllegalArgumentException(String.format( "Encode version length: '%s' is not valid, it must be greater of equal to 0", encodeVersionLength)); } if (!value.substring(1, 1 + encodeVersionLength).equals(ENCODE_VERSION)) { throw new IllegalArgumentException(String.format( "Encode version received was: '%s', Encode version supported is: '%s'", value, ENCODE_VERSION)); } final byte[] bytes = Base64.decode(value.substring(1 + encodeVersionLength), Base64.DEFAULT); String keyVersionCheck = new String(bytes, 0, KEY_VERSION_BLOB_LENGTH, AuthenticationConstants.ENCODING_UTF8); SecretKey versionKey = getKeyForVersion(keyVersionCheck); SecretKey versionMacKey = getMacKey(versionKey); int ivIndex = bytes.length - DATA_KEY_LENGTH - MAC_LENGTH; int macIndex = bytes.length - MAC_LENGTH; int encryptedLength = ivIndex - KEY_VERSION_BLOB_LENGTH; if (ivIndex < 0 || macIndex < 0 || encryptedLength < 0) { throw new IllegalArgumentException( "Given value is smaller than the IV vector and MAC length"); } Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); Mac mac = Mac.getInstance(MAC_ALGORITHM); mac.init(versionMacKey); mac.update(bytes, 0, macIndex); byte[] macDigest = mac.doFinal(); assertMac(bytes, macIndex, bytes.length, macDigest); cipher.init(Cipher.DECRYPT_MODE, versionKey, new IvParameterSpec(bytes, ivIndex, DATA_KEY_LENGTH)); String decrypted = new String(cipher.doFinal(bytes, KEY_VERSION_BLOB_LENGTH, encryptedLength), AuthenticationConstants.ENCODING_UTF8); Logger.d(TAG, "Finished decryption"); return decrypted; }