juliansteenbakker / flutter_secure_storage

A Flutter plugin to store data in secure storage
https://pub.dartlang.org/packages/flutter_secure_storage
BSD 3-Clause "New" or "Revised" License
1.13k stars 389 forks source link

PlatformException: Code: -25308. Help me! #727

Open gamestap99 opened 6 months ago

gamestap99 commented 6 months ago

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));
techouse commented 6 months ago

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.?

gamestap99 commented 6 months ago

@techouse Oke. Project using :

abhinand-kv commented 6 months ago

facing the same issue

flutter version: 3.19.3 flutter_secure_storage: 9.2.2

techouse commented 6 months ago

@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
germinator1512 commented 5 months ago

Facing the Same Issue

FLutter: 3.22.0
flutter_secure_storage: ^9.2.1
Device: Iphone 15 Pro  IOS(v17.4.1)
starshipcoder commented 5 months ago

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

koutja commented 5 months ago

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 %

oleksiyPetlyuk commented 5 months ago

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.

marcotta commented 5 months ago

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
Reprevise commented 5 months ago

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?

oleksiyPetlyuk commented 5 months ago

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

DmitryGaimaldinov commented 3 months ago

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

revtut commented 2 months ago

We are also getting that crash after upgrading to the v9.2.2 version.

Screenshot 2024-09-19 at 09 04 39
amrLLSE commented 2 months ago

Facing same issue on latest version.

bbeckley commented 1 month ago

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());

Tom3652 commented 1 month ago

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)
);
jostney commented 3 weeks ago

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!

btrautmann commented 3 weeks ago

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.

jostney commented 3 weeks ago

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,

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

btrautmann commented 3 weeks ago

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

jostney commented 3 weeks ago

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?

btrautmann commented 3 weeks ago

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.