flutter_secure_storage icon indicating copy to clipboard operation
flutter_secure_storage copied to clipboard

PlatformException: Code: -25308. Help me!

Open gamestap99 opened this issue 1 year ago • 16 comments

On a beautiful day, I received this token, and it seems that it caused my app to crash. To be more precise, I tried to catch the error, so it didn't take the main key, causing the session to log out. I am using it to encrypt the Hive NoSQL database. Screenshot 2024-05-27 at 19 21 09

my code using it

 // Create key and encryption
    FlutterSecureStorage secureStorage = const FlutterSecureStorage();
    String? secureStorageKey;
    late List<int> encryptionKey;
    String storeKey = AppConfig.storeKey(isDev: F.appFlavor == Flavor.beta);

    /** @see: https://github.com/mogol/flutter_secure_storage/issues/84*/
    try {
      secureStorageKey = await secureStorage.read(key: storeKey);

      Helpers.dump('secureStorageKey value: $secureStorageKey', line: true);
    } catch (ex, stackTrace) {
      Helpers.reportSentry(ex, stackTrace);

      await secureStorage.delete(key: storeKey);
    }

    if ((secureStorageKey?.isEmpty ?? true)) {
      await secureStorage.delete(key: storeKey);

      var key = Hive.generateSecureKey();

      Helpers.dump('Before Write Key value: $key', line: true);
      Helpers.dump('Before Write secureStorageKey value: ${base64UrlEncode(key)}', line: true);

      await secureStorage.write(
        key: storeKey,
        value: base64UrlEncode(key),
      );

      Helpers.dump('Write success key: $key', line: true);

      encryptionKey = key;
    }else{
      secureStorageKey = await secureStorage.read(key: storeKey);
      encryptionKey = base64Url.decode(secureStorageKey ?? '');
    }


    Helpers.dump('Encryption key: $encryptionKey', line: true);

    //Open Boxes
    await Hive.openBox<UserHiveModel>(UserHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<SettingHiveModel>(SettingHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<GeotrackHiveModel>(GeotrackHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<MAccessTokenHive>(MAccessTokenHive.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<ProjectHiveModel>(ProjectHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<ActionPostHiveModel>(ActionPostHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<PostHiveModel>(PostHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));
    await Hive.openBox<MediaHiveModel>(MediaHiveModel.boxKey, encryptionCipher: HiveAesCipher(encryptionKey));

gamestap99 avatar May 27 '24 12:05 gamestap99

Error -25308 is errSecInteractionNotAllowed.

You might want to read this post on the Apple Developer Forums.

Can you give us some more context, i.e. the OS, version etc.?

techouse avatar May 27 '24 18:05 techouse

@techouse Oke. Project using :

  • FLutter: 3.22.0
  • flutter_secure_storage: ^9.2.2
  • Device: Iphone 11 Pro(arm64) x IOS(v17.4.1)

gamestap99 avatar May 28 '24 04:05 gamestap99

facing the same issue

flutter version: 3.19.3 flutter_secure_storage: 9.2.2

abhinand-kv avatar May 28 '24 10:05 abhinand-kv

@gamestap99 Can you replicate this on a simulator or provide us with some sample code that replicates this error?

Does it work with v9.0.0 using something like this?

dependency_overrides:
  flutter_secure_storage: 9.0.0
  flutter_secure_storage_linux: 1.2.0
  flutter_secure_storage_macos: 3.0.1
  flutter_secure_storage_platform_interface: 1.0.2
  flutter_secure_storage_windows: 3.0.0
  flutter_secure_storage_web:  1.2.0

techouse avatar May 28 '24 11:05 techouse

Facing the Same Issue

FLutter: 3.22.0
flutter_secure_storage: ^9.2.1
Device: Iphone 15 Pro  IOS(v17.4.1)

germinator1512 avatar May 29 '24 07:05 germinator1512

Same issue for one customer, bug not always flutter_secure_storage: 9.2.2 iOS 16.7.8

starshipcoder avatar May 31 '24 13:05 starshipcoder

Same issue for some customers, bug not always, after read data when device was unlocked flutter_secure_storage: 9.2.2

iOS 17.5.1 - 43,75 % iOS 17.4.1- 31,25 % iOS 16.5 - 25 %

koutja avatar Jun 04 '24 08:06 koutja

This issue is replicable by reading from a secure storage(keychain) when a device is locked and has a passcode.

It can be fixed with:

final _storageProvider = FlutterSecureStorage(
    iOptions: IOSOptions.defaultOptions.copyWith(
      accessibility: KeychainAccessibility.first_unlock_this_device,
      synchronizable: true,
    ),
  );

Note: Without providing synchronizable: true it throws the errSecDuplicateItem platform exception for me.

oleksiyPetlyuk avatar Jun 04 '24 17:06 oleksiyPetlyuk

Issue disappeared when I downgraded the library:

dependency_overrides:
  # Downgrade secure storage to 9.0.0 as version 9.2.2 has introduced some crashes on iOS
  # The error description is "Unexpected security result code, Code: -25308"
  flutter_secure_storage: 9.0.0
  flutter_secure_storage_linux: 1.2.0
  flutter_secure_storage_macos: 3.0.1
  flutter_secure_storage_platform_interface: 1.0.2
  flutter_secure_storage_web: 1.1.2
  flutter_secure_storage_windows: 3.0.0

marcotta avatar Jun 06 '24 10:06 marcotta

This issue is replicable by reading from a secure storage(keychain) when a device is locked and has a passcode.

It can be fixed with:

final _storageProvider = FlutterSecureStorage(
    iOptions: IOSOptions.defaultOptions.copyWith(
      accessibility: KeychainAccessibility.first_unlock_this_device,
      synchronizable: true,
    ),
  );

Note: Without providing synchronizable: true it throws the errSecDuplicateItem platform exception for me.

What are the consequences of doing this?

Reprevise avatar Jun 21 '24 00:06 Reprevise

This issue is replicable by reading from a secure storage(keychain) when a device is locked and has a passcode. It can be fixed with:

final _storageProvider = FlutterSecureStorage(
    iOptions: IOSOptions.defaultOptions.copyWith(
      accessibility: KeychainAccessibility.first_unlock_this_device,
      synchronizable: true,
    ),
  );

Note: Without providing synchronizable: true it throws the errSecDuplicateItem platform exception for me.

What are the consequences of doing this?

https://developer.apple.com/documentation/security/ksecattraccessibleafterfirstunlock

oleksiyPetlyuk avatar Jun 21 '24 14:06 oleksiyPetlyuk

@mogol, please, can you explain why this happens and can it be fixed by someone?

DmitryGaimaldinov avatar Aug 06 '24 13:08 DmitryGaimaldinov

We are also getting that crash after upgrading to the v9.2.2 version. Screenshot 2024-09-19 at 09 04 39

revtut avatar Sep 19 '24 08:09 revtut

Facing same issue on latest version.

amrLLSE avatar Sep 22 '24 12:09 amrLLSE

Facing same issue as well on latest version for some iOS devices with the options fix set.

IOSOptions _getIOSOptions() => const IOSOptions( accessibility: KeychainAccessibility.first_unlock, synchronizable: true, accountName: 'myapp_prefs', );

await _secureStorage.write(key: newItem.key.name, value: newItem.value, aOptions: _getAndroidOptions(), iOptions: _getIOSOptions());

bbeckley avatar Sep 28 '24 13:09 bbeckley

Having the same issue with this initialization but only in release mode in my live app :

 final FlutterSecureStorage _secureStorage = const FlutterSecureStorage(
      aOptions: AndroidOptions(
        encryptedSharedPreferences: true,
      ),
      iOptions: IOSOptions(synchronizable: false)
);

Tom3652 avatar Oct 20 '24 13:10 Tom3652

I changed my usage from

final storage = const FlutterSecureStorage(aOptions: AndroidOptions(encryptedSharedPreferences: true));

to

final _storage = const FlutterSecureStorage(
  aOptions: AndroidOptions(encryptedSharedPreferences: true),
  iOptions: IOSOptions(
    accessibility: KeychainAccessibility.first_unlock_this_device,
    synchronizable: true,
  ),
);

Seems the problem didn't happen but behaved values aren't stored anymore before!

jostney avatar Oct 28 '24 09:10 jostney

Seems the problem didn't happen but behaved values aren't stored anymore before!

When changing the settings, you need to "migrate" values from the previous settings. I described this in a similar issue.

btrautmann avatar Oct 28 '24 19:10 btrautmann

Seems the problem didn't happen but behaved values aren't stored anymore before!

When changing the settings, you need to "migrate" values from the previous settings. I described this in a similar issue.

I've just reviewed your metod, it simply uses secure storage first, then uses legacy (shared prefs imho) if secure storage fails. This means same values are stored (must be stored) in secure storage and legacy options both, otherwise this fallback does not work.

In my scenario,

  • App is terminated and device is locked.
  • App receives video call on lock screen and user accepts it.
  • App starts and gets user credentials from secure storage. -----> Here booms

To make work your scenario i would be storing those credentials in "legacy" option too :/

jostney avatar Oct 28 '24 20:10 jostney

I've just reviewed your metod, it simply uses secure storage first, then uses legacy (shared prefs imho) if secure storage fails. This means same values are stored (must be stored) in secure storage and legacy options both, otherwise this fallback does not work.

No, it's using secure storage in both cases. "Legacy" refers to the secure storage being created/accessed with the old settings. Here's the associated code:

Screenshot 2024-10-28 at 16 57 52

btrautmann avatar Oct 28 '24 20:10 btrautmann

Yes, my mistake. Both storages are indeed FlutterSecureStorage.

Based on your latest post, it looks like _legacyStorage is the one I’ve already been using, and it’s throwing the 25308 exception.

I also tried _storage (as I mentioned in my first post), but it returns empty for all my keys.

To sum up, using _storage first and getting an empty result, then trying _legacyStorage and getting the 25308 exception, doesn't add up. How would this resolve the issue?

jostney avatar Oct 28 '24 21:10 jostney

Yes, my mistake. Both storages are indeed FlutterSecureStorage.

Based on your latest post, it looks like _legacyStorage is the one I’ve already been using, and it’s throwing the 25308 exception.

I also tried _storage (as I mentioned in my first post), but it returns empty for all my keys.

To sum up, using _storage first and getting an empty result, then trying _legacyStorage and getting the 25308 exception, doesn't add up. How would this resolve the issue?

In my case, if the app was restarted, the storage was accessible again...It was reading from the background that was messing things up. If in your case the "legacy" storage is fully borked and you can no longer read from it, migration may not be possible.

btrautmann avatar Oct 29 '24 14:10 btrautmann

The error is due to data being requested while it is not allowed to, defined via accessibility: KeychainAccessibility....

If you want to read data while the app is in the background, please change the accessibility parameter to the correct setting.

juliansteenbakker avatar Jan 06 '25 15:01 juliansteenbakker

The error is due to data being requested while it is not allowed to, defined via accessibility: KeychainAccessibility....

If you want to read data while the app is in the background, please change the accessibility parameter to the correct setting.

Hi there, which parameter do we have to use then? (in case we want to access the keychain in the background + screen locked)

bummsa avatar Jan 24 '25 15:01 bummsa

Using first_unlock or first_unlock_this_device the item will become available after the first unlock (when the device is booted), so it will always be accessible if locked after first unlock. See https://github.com/juliansteenbakker/flutter_secure_storage/blob/97fbb0eb766aaf818e91bca5d71e702589545945/flutter_secure_storage/lib/options/apple_options.dart#L24

And https://developer.apple.com/documentation/security/item-attribute-keys-and-values#Accessibility-Values

juliansteenbakker avatar Jan 24 '25 15:01 juliansteenbakker

Using first_unlock or first_unlock_this_device the item will become available after the first unlock (when the device is booted), so it will always be accessible if locked after first unlock. See

flutter_secure_storage/flutter_secure_storage/lib/options/apple_options.dart

Line 24 in 97fbb0e

first_unlock, And https://developer.apple.com/documentation/security/item-attribute-keys-and-values#Accessibility-Values

Perfect, thank you! Another question: is it mandatory to reinstall the app to apply the new first_unlock configuration?

I have this behaviour: I have a ping timer running in the background that requires authentication. In case the access token has expired, a new one is requested, but to do that, I need to access the secure storage once. For some reason, with first_unlock option I still have the behavior where it throws the PlatformException.

This behaviour is not there when I reinstall the app.

bummsa avatar Jan 29 '25 09:01 bummsa

i am getting this isue after adding first unlock PlatformException(Unexpected security result code, Code: -25299, Message: The specified item already exists in the keychain., -25299, null).

@juliansteenbakker

eshan028 avatar Mar 20 '25 05:03 eshan028