【发布时间】: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