Skip to content

Commit 733b438

Browse files
committed
fix(app): flag to force strongbox by removing fallback
1 parent be1fdce commit 733b438

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class FlutterSecureStorage {
3333
private static final String PREF_OPTION_PREFIX = "preferencesKeyPrefix";
3434
private static final String PREF_OPTION_DELETE_ON_FAILURE = "resetOnError";
3535
private static final String PREF_KEY_MIGRATED = "preferencesMigrated";
36+
private static final String PREF_OPTION_ONLY_ALLOW_STRONGBOX = "onlyAllowStrongBox";
3637
@NonNull
3738
private final SharedPreferences encryptedPreferences;
3839
@NonNull
@@ -63,7 +64,15 @@ public FlutterSecureStorage(Context context, Map<String, Object> options) throws
6364
}
6465
}
6566

66-
encryptedPreferences = getEncryptedSharedPreferences(deleteOnFailure, options, context.getApplicationContext(), sharedPreferencesName, true);
67+
boolean onlyAllowStrongbox = false;
68+
if (options.containsKey(PREF_OPTION_ONLY_ALLOW_STRONGBOX)) {
69+
var value = options.get(PREF_OPTION_ONLY_ALLOW_STRONGBOX);
70+
if (value instanceof String) {
71+
onlyAllowStrongbox = Boolean.parseBoolean((String) value);
72+
}
73+
}
74+
75+
encryptedPreferences = getEncryptedSharedPreferences(deleteOnFailure, options, context.getApplicationContext(), sharedPreferencesName, true, onlyAllowStrongbox);
6776
}
6877

6978
public boolean containsKey(String key) {
@@ -104,7 +113,7 @@ private String addPrefixToKey(String key) {
104113
return preferencesKeyPrefix + "_" + key;
105114
}
106115

107-
private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure, Map<String, Object> options, Context context, String sharedPreferencesName, boolean isStrongBoxBacked) throws GeneralSecurityException, IOException {
116+
private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure, Map<String, Object> options, Context context, String sharedPreferencesName, boolean isStrongBoxBacked, boolean isOnlyStrongBoxAllowed) throws GeneralSecurityException, IOException {
108117
try {
109118
final SharedPreferences encryptedPreferences = initializeEncryptedSharedPreferencesManager(context, sharedPreferencesName, isStrongBoxBacked);
110119
boolean migrated = encryptedPreferences.getBoolean(PREF_KEY_MIGRATED, false);
@@ -117,7 +126,7 @@ private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure,
117126
Throwable cause = e.getCause();
118127

119128
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
120-
if (cause instanceof StrongBoxUnavailableException) {
129+
if (cause instanceof StrongBoxUnavailableException && !isOnlyStrongBoxAllowed) {
121130
// Fallback to not using Strongbox
122131
return getEncryptedSharedPreferences(deleteOnFailure, options, context, sharedPreferencesName, false);
123132
}

flutter_secure_storage/lib/options/android_options.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ class AndroidOptions extends Options {
2727
StorageCipherAlgorithm.AES_CBC_PKCS7Padding,
2828
this.sharedPreferencesName,
2929
this.preferencesKeyPrefix,
30+
bool onlyAllowStrongBox = false,
3031
}) : _encryptedSharedPreferences = encryptedSharedPreferences,
3132
_resetOnError = resetOnError,
3233
_keyCipherAlgorithm = keyCipherAlgorithm,
33-
_storageCipherAlgorithm = storageCipherAlgorithm;
34+
_storageCipherAlgorithm = storageCipherAlgorithm,
35+
_onlyAllowStrongBox = onlyAllowStrongBox;
3436

3537
/// EncryptedSharedPrefences are only available on API 23 and greater
3638
final bool _encryptedSharedPreferences;
@@ -70,6 +72,12 @@ class AndroidOptions extends Options {
7072
/// WARNING: If you change this you can't retrieve already saved preferences.
7173
final String? preferencesKeyPrefix;
7274

75+
/// If true, only allow keys to be stored in StrongBox backed keymaster.
76+
/// This option is only available on API 28 and greater. If set to true some phones might now work
77+
/// Defaults to false.
78+
/// https://developer.android.com/training/articles/keystore#HardwareSecurityModule
79+
final bool _onlyAllowStrongBox;
80+
7381
static const AndroidOptions defaultOptions = AndroidOptions();
7482

7583
@override
@@ -80,6 +88,7 @@ class AndroidOptions extends Options {
8088
'storageCipherAlgorithm': _storageCipherAlgorithm.name,
8189
'sharedPreferencesName': sharedPreferencesName ?? '',
8290
'preferencesKeyPrefix': preferencesKeyPrefix ?? '',
91+
'onlyAllowStrongBox': '$_onlyAllowStrongBox',
8392
};
8493

8594
AndroidOptions copyWith({
@@ -89,6 +98,7 @@ class AndroidOptions extends Options {
8998
StorageCipherAlgorithm? storageCipherAlgorithm,
9099
String? preferencesKeyPrefix,
91100
String? sharedPreferencesName,
101+
bool? onlyAllowStrongBox,
92102
}) =>
93103
AndroidOptions(
94104
encryptedSharedPreferences:
@@ -99,5 +109,6 @@ class AndroidOptions extends Options {
99109
storageCipherAlgorithm ?? _storageCipherAlgorithm,
100110
sharedPreferencesName: sharedPreferencesName,
101111
preferencesKeyPrefix: preferencesKeyPrefix,
112+
onlyAllowStrongBox: onlyAllowStrongBox ?? _onlyAllowStrongBox,
102113
);
103114
}

0 commit comments

Comments
 (0)