Skip to content

Commit b72b981

Browse files
grafeleclaude
andcommitted
fix(android): broaden StrongBox fallback and delete corrupted Keystore key on reset
- Catch any GeneralSecurityException when StrongBox is enabled, not just StrongBoxUnavailableException. Devices like Xiaomi Redmi Note 15 Pro+ throw a plain GeneralSecurityException wrapping a RESET_FAILED error, which was not caught by the previous narrower check. - When resetOnError triggers a storage reset, also delete the corrupted master key entry from the Android Keystore before retrying. This fixes Keystore2 migration corruption on devices like Galaxy S10e (Android 12). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6f6ac1a commit b72b981

1 file changed

Lines changed: 11 additions & 10 deletions

File tree

flutter_secure_storage/android/src/main/java/com/it_nomads/fluttersecurestorage/FlutterSecureStorage.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import android.os.Build;
66
import android.security.keystore.KeyGenParameterSpec;
77
import android.security.keystore.KeyProperties;
8-
import android.security.keystore.StrongBoxUnavailableException;
98
import android.util.Base64;
109
import android.util.Log;
1110

@@ -123,15 +122,9 @@ private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure,
123122
}
124123
return encryptedPreferences;
125124
} catch (GeneralSecurityException | IOException e) {
126-
if (e instanceof GeneralSecurityException) {
127-
Throwable cause = e.getCause();
128-
129-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
130-
if (cause instanceof StrongBoxUnavailableException && !isOnlyStrongBoxAllowed) {
131-
// Fallback to not using Strongbox
132-
return getEncryptedSharedPreferences(deleteOnFailure, options, context, sharedPreferencesName, false, isOnlyStrongBoxAllowed);
133-
}
134-
}
125+
if (e instanceof GeneralSecurityException && isStrongBoxBacked && !isOnlyStrongBoxAllowed) {
126+
Log.w(TAG, "StrongBox-backed key generation failed, retrying without StrongBox", e);
127+
return getEncryptedSharedPreferences(deleteOnFailure, options, context, sharedPreferencesName, false, isOnlyStrongBoxAllowed);
135128
}
136129

137130
if (!deleteOnFailure) {
@@ -141,6 +134,14 @@ private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure,
141134
Log.w(TAG, "initialization failed, resetting storage", e);
142135

143136
context.getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE).edit().clear().apply();
137+
// Also remove corrupted master key from Android Keystore
138+
try {
139+
java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
140+
keyStore.load(null);
141+
keyStore.deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS);
142+
} catch (Exception ignored) {
143+
Log.w(TAG, "Failed to delete master key from KeyStore", ignored);
144+
}
144145

145146
try {
146147
return initializeEncryptedSharedPreferencesManager(context, sharedPreferencesName, isStrongBoxBacked);

0 commit comments

Comments
 (0)