【问题标题】:AEADBadTagException while decrypting解密时出现 AEADBadTagException
【发布时间】:2019-12-04 09:49:32
【问题描述】:

我在这里发现了许多类似的问题,但没有一个建议对我有用。我在登录应用程序并尝试在我的应用程序的其他部分解密时使用密钥库加密用户密码。加密工作正常,但在尝试解密该值时,我收到 AEADBadTagException。

我的代码如下。

加密方式。

@RequiresApi(api = Build.VERSION_CODES.M)
private void encryptText() {
    try {
        final byte[] encryptedText = encryptor
                .encryptText("MY_ALIAS",mPsd.toString());
    } catch (UnrecoverableEntryException | NoSuchAlgorithmException | NoSuchProviderException |
            KeyStoreException | IOException | NoSuchPaddingException | InvalidKeyException e) {
    } catch (InvalidAlgorithmParameterException | SignatureException |
            IllegalBlockSizeException | BadPaddingException e) {
        e.printStackTrace();
    }
}

加密器类:

public class EnCryptor {
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";

private byte[] encryption;
private byte[] iv;

public EnCryptor() {
}
@RequiresApi(api = Build.VERSION_CODES.M)
public byte[] encryptText(final String alias, final String textToEncrypt)
        throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
        NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException,
        InvalidAlgorithmParameterException, SignatureException, BadPaddingException,
        IllegalBlockSizeException {

    final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias));

    iv = cipher.getIV();
    encryption = cipher.doFinal(textToEncrypt.getBytes("UTF-8"));
    SharedPreferencesManager.getInstance().saveEncrypt(Base64.encodeToString(encryption, Base64.DEFAULT));
    SharedPreferencesManager.getInstance().saveEncrypted_iv(Base64.encodeToString(iv, Base64.DEFAULT));
    return (encryption);

}

@RequiresApi(api = Build.VERSION_CODES.M)
@NonNull
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException,
        NoSuchProviderException, InvalidAlgorithmParameterException {

    final KeyGenerator keyGenerator = KeyGenerator
            .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
    keyGenerator.init(new KeyGenParameterSpec.Builder(alias,
            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build());
    return keyGenerator.generateKey();
}
public byte[] getEncryption() {
    return encryption;
}
public byte[] getIv() {
    return iv;
}
}

上述加密部分正常工作。我稍后在我的应用程序中尝试解密该值的方式如下:

从 Fragment 调用方法:

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private char[] decryptText() {
    try {
        String txt = decryptor.decryptData("MY_ALIAS",
                Base64.decode(SharedPreferencesManager.getInstance().getEncrypt(), Base64.DEFAULT),
                Base64.decode(SharedPreferencesManager.getInstance().getEncrypted_iv(), Base64.DEFAULT));
        return txt.toCharArray();
    } catch (UnrecoverableEntryException | NoSuchAlgorithmException |
            KeyStoreException | NoSuchPaddingException | NoSuchProviderException |
            IOException | InvalidKeyException e) {
    } catch (IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return "".toCharArray();
}

DeCryptor 类如下。这里只有我得到了例外

public class DeCryptor {

private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private KeyStore keyStore;
public DeCryptor() throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
        IOException {
    initKeyStore();
}
private void initKeyStore() throws KeyStoreException, CertificateException,
        NoSuchAlgorithmException, IOException {
    keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
    try {
        keyStore.load(null);
    } catch (java.security.cert.CertificateException e) {
        e.printStackTrace();
    }
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public String decryptData(final String alias, final byte[] encryptedData, final byte[] encryptionIv)
        throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
        NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException,
        BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {

    final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv);
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec);
    return new String(cipher.doFinal(encryptedData), "UTF-8");
}
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException,
        UnrecoverableEntryException, KeyStoreException {
    return ((KeyStore.SecretKeyEntry) keyStore.getEntry(alias, null)).getSecretKey();
}
}

在加密时,加密的数据和 iv 被存储到共享首选项中,以便在解密时也可以使用它。 当我尝试从相同的活动中加密和解密时,它工作正常,这个问题仅在尝试在应用程序的其他部分解密时发生。 任何帮助表示赞赏。

【问题讨论】:

  • 你能分享一个完整的测试应用来演示这个问题吗?
  • 有同样的问题。如果我在没有 IV 的情况下加密就可以工作。将其保存在共享首选项中。然后我从 sharedPrefs 获取 IV。用它创建 GCMParameterSpec。并调用 doFinal() 但我得到 AEADBadTagException。当我按顺序执行加密和解密而不重新启动活动时工作正常。

标签: android android-keystore aes-gcm


【解决方案1】:

如果问题仅发生在此设备上,而不是其他设备上,则可能是由于您没有注意线程安全问题,因此您的应用程序的 Android 密钥库已锁定。 Android 密钥库不是线程安全的。 以下是对我有用的解决方案:

  1. 在AndroidManifest.xml文件中添加allowBackupfalse
<application
    android:allowBackup="false"
...
>
  1. 使用 synchronized 封装所有 Android 密钥库操作。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2011-01-31
  • 1970-01-01
相关资源
最近更新 更多