22
33import android .content .Context ;
44import android .content .SharedPreferences ;
5+ import android .os .Build ;
56import android .security .keystore .KeyGenParameterSpec ;
67import android .security .keystore .KeyProperties ;
8+ import android .security .keystore .StrongBoxUnavailableException ;
79import android .util .Base64 ;
810import android .util .Log ;
911
@@ -61,7 +63,7 @@ public FlutterSecureStorage(Context context, Map<String, Object> options) throws
6163 }
6264 }
6365
64- encryptedPreferences = getEncryptedSharedPreferences (deleteOnFailure , options , context .getApplicationContext (), sharedPreferencesName );
66+ encryptedPreferences = getEncryptedSharedPreferences (deleteOnFailure , options , context .getApplicationContext (), sharedPreferencesName , true );
6567 }
6668
6769 public boolean containsKey (String key ) {
@@ -102,15 +104,25 @@ private String addPrefixToKey(String key) {
102104 return preferencesKeyPrefix + "_" + key ;
103105 }
104106
105- private SharedPreferences getEncryptedSharedPreferences (boolean deleteOnFailure , Map <String , Object > options , Context context , String sharedPreferencesName ) throws GeneralSecurityException , IOException {
107+ private SharedPreferences getEncryptedSharedPreferences (boolean deleteOnFailure , Map <String , Object > options , Context context , String sharedPreferencesName , boolean isStrongBoxBacked ) throws GeneralSecurityException , IOException {
106108 try {
107- final SharedPreferences encryptedPreferences = initializeEncryptedSharedPreferencesManager (context , sharedPreferencesName );
109+ final SharedPreferences encryptedPreferences = initializeEncryptedSharedPreferencesManager (context , sharedPreferencesName , isStrongBoxBacked );
108110 boolean migrated = encryptedPreferences .getBoolean (PREF_KEY_MIGRATED , false );
109111 if (!migrated ) {
110112 migrateToEncryptedPreferences (context , sharedPreferencesName , encryptedPreferences , deleteOnFailure , options );
111113 }
112114 return encryptedPreferences ;
113115 } catch (GeneralSecurityException | IOException e ) {
116+ if (e instanceof GeneralSecurityException ) {
117+ Throwable cause = e .getCause ();
118+
119+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .P ) {
120+ if (cause instanceof StrongBoxUnavailableException ) {
121+ // Fallback to not using Strongbox
122+ return getEncryptedSharedPreferences (deleteOnFailure , options , context , sharedPreferencesName , false );
123+ }
124+ }
125+ }
114126
115127 if (!deleteOnFailure ) {
116128 Log .w (TAG , "initialization failed, resetOnError false, so throwing exception." , e );
@@ -121,24 +133,29 @@ private SharedPreferences getEncryptedSharedPreferences(boolean deleteOnFailure,
121133 context .getSharedPreferences (sharedPreferencesName , Context .MODE_PRIVATE ).edit ().clear ().apply ();
122134
123135 try {
124- return initializeEncryptedSharedPreferencesManager (context , sharedPreferencesName );
136+ return initializeEncryptedSharedPreferencesManager (context , sharedPreferencesName , isStrongBoxBacked );
125137 } catch (Exception f ) {
126138 Log .e (TAG , "initialization after reset failed" , f );
127139 throw f ;
128140 }
129141 }
130142 }
131143
132- private SharedPreferences initializeEncryptedSharedPreferencesManager (Context context , String sharedPreferencesName ) throws GeneralSecurityException , IOException {
144+ private SharedPreferences initializeEncryptedSharedPreferencesManager (Context context , String sharedPreferencesName , boolean isStrongBoxBacked ) throws GeneralSecurityException , IOException {
145+ KeyGenParameterSpec .Builder keyGenBuilder = new KeyGenParameterSpec .Builder (
146+ MasterKey .DEFAULT_MASTER_KEY_ALIAS ,
147+ KeyProperties .PURPOSE_ENCRYPT | KeyProperties .PURPOSE_DECRYPT )
148+ .setBlockModes (KeyProperties .BLOCK_MODE_GCM )
149+ .setEncryptionPaddings (KeyProperties .ENCRYPTION_PADDING_NONE )
150+ .setKeySize (256 );
151+
152+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .P && isStrongBoxBacked ) {
153+ keyGenBuilder .setIsStrongBoxBacked (true );
154+ }
155+
133156 MasterKey masterKey = new MasterKey .Builder (context )
134- .setKeyGenParameterSpec (new KeyGenParameterSpec .Builder (
135- MasterKey .DEFAULT_MASTER_KEY_ALIAS ,
136- KeyProperties .PURPOSE_ENCRYPT | KeyProperties .PURPOSE_DECRYPT )
137- .setBlockModes (KeyProperties .BLOCK_MODE_GCM )
138- .setEncryptionPaddings (KeyProperties .ENCRYPTION_PADDING_NONE )
139- .setKeySize (256 )
140- .build ())
141- .build ();
157+ .setKeyGenParameterSpec (keyGenBuilder .build ())
158+ .build (isStrongBoxBacked );
142159
143160 return EncryptedSharedPreferences .create (
144161 context ,
0 commit comments