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.14k stars 391 forks source link

v7.0.0 Upgraded from v6.0.0 is not working [Tested on Android Device Only] #487

Closed bamakant closed 3 months ago

bamakant commented 1 year ago

While reading the data from Flutter Secure Storage getting the below exception.

I/flutter (31903): PlatformException(Exception encountered, read, java.lang.ArrayIndexOutOfBoundsException: src.length=6 srcPos=0 dst.length=16 dstPos=0 length=16
I/flutter (31903):  at java.lang.System.arraycopy(Native Method)
I/flutter (31903):  at com.it_nomads.fluttersecurestorage.ciphers.StorageCipher18Implementation.decrypt(StorageCipher18Implementation.java:84)
I/flutter (31903):  at com.it_nomads.fluttersecurestorage.FlutterSecureStorage.decodeRawValue(FlutterSecureStorage.java:243)
I/flutter (31903):  at com.it_nomads.fluttersecurestorage.FlutterSecureStorage.read(FlutterSecureStorage.java:65)
I/flutter (31903):  at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin$MethodRunner.run(FlutterSecureStoragePlugin.java:156)
I/flutter (31903):  at android.os.Handler.handleCallback(Handler.java:938)
I/flutter (31903):  at android.os.Handler.dispatchMessage(Handler.java:99)
I/flutter (31903):  at android.os.Looper.loopOnce(Looper.java:201)
I/flutter (31903):  at android.os.Looper.loop(Looper.java:288)
I/flutter (31903):  at android.os.HandlerThread.run(HandlerThread.java:67)
I/flutter (31903): , null)

FYI: Tested on Android only

I can't see any specific changes need to do after upgrading to v.7.0.0.

Please let me know if I am missing any specific changes to make.

adil192 commented 1 year ago

Just to add to this, it's working on Linux but not Android for me (values aren't saved). Downgrading to 6.1.0 fixes this

juliansteenbakker commented 1 year ago

Are you using encryptedSharedPreferences: true? And are you also passing this to the read() function? I can recreate this error when calling readAll() with encryptedSharedPreferences: true, but after that calling 'read()` without it.

bamakant commented 1 year ago

@juliansteenbakker I am usingencryptedSharedPreferences: true and also passing this to read() function. It was working fine till v6.1.0

juliansteenbakker commented 1 year ago

and are you passing this to all the other functions aswell, like readall(), write(), containsKey() or delete()?

EDIT: Or are you using it in the constructor like: FlutterSecureStorage(aOptions: AndroidOptions)

adil192 commented 1 year ago

I wasn't using any aOptions: code snippet

  // simplified

  @override
  Future<T?> _load() async {
    _storage ??= const FlutterSecureStorage();

    String value = await _storage!.read(key: key);
    ...
  }

  @override
  Future _save() async {
    _storage ??= const FlutterSecureStorage();

    return await _storage!.write(key: key, value: value as String);
  }
bamakant commented 1 year ago

It seems to passing aOptions is mandatory from v7.0.0 as I also found one read() function not passing aOptions and adding this fixed the mentioned issue above.

EDIT: Or are you using it in the constructor like: FlutterSecureStorage(aOptions: AndroidOptions) - No I am passing aOptions with functions(read, write etc) only @juliansteenbakker

juliansteenbakker commented 1 year ago

So the problem here is that a value gets saved with the EncryptedSharedPreferences library, but gets read without the 'encryptedSharedPreferences` parameter. This will cause the plugin to think additional decrypting is needed, while it is already decrypted. Hence why the decryption process failes.

With version 6.0.0 and lower, the internal SharedPreference object was reloaded everytime a call was done (like read() or write()). This is why mixed usage of the options parameter worked fine. HOWEVER, this changed with version 7.0.0 because this kind of mixed usage can cause unwanted behaviour when using functions like containsKey(), which can only check SharedPreference OR SecureSharedPerference but not both at the same time.

This change however breaks the usage of mixed options usage. Which is why a. I need to let the internal sharedPreference object refresh everytime, but keep problems with containsKey() b. OR: remove the options parameter from every single function, and only allow passing it to the constructor.

@adil192 In your case the keys and values already exists in the SecureSharedPreference object because you are using another plugin. However, FlutterSecureStorage() doesn't know this so it still tries to decode it, even when it's decoded already and so it throws the error.

juliansteenbakker commented 1 year ago

I have published v7.0.1 which applied option a. of the above comment. For option B to work we will need to publish a new breaking version.

bamakant commented 1 year ago

@juliansteenbakker Thanks for your quick support. I am not facing the issue with v7.0.1 anymore.

juliansteenbakker commented 3 months ago

I am closing all older issues. If this issue still exists in the latest version, please let me know.