Flutter Secure Storage Platform Exception

5.1k Views Asked by At

I'm using flutter secure storage (^5.0.2) to save tokens but I'm getting the following error when storage.write() is called on an emulator (I'm using Pixel 5 API 30) whereas when I use it on my physical device (Honor 8x) it's working well :

PlatformException (PlatformException(Exception encountered, write, java.lang.NullPointerException: Attempt to invoke interface method 'byte[] com.it_nomads.fluttersecurestorage.ciphers.StorageCipher.encrypt(byte[])' on a null object reference
    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.write(FlutterSecureStoragePlugin.java:202)
    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.access$300(FlutterSecureStoragePlugin.java:37)
    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin$MethodRunner.run(FlutterSecureStoragePlugin.java:289)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.os.HandlerThread.run(HandlerThread.java:67)
, null))

Here is the output of the debug :

W/KeyStore( 2975): KeyStore exception
W/KeyStore( 2975): android.os.ServiceSpecificException:  (code 7)
W/KeyStore( 2975):  at android.os.Parcel.createExceptionOrNull(Parcel.java:2387)
W/KeyStore( 2975):  at android.os.Parcel.createException(Parcel.java:2357)
W/KeyStore( 2975):  at android.os.Parcel.readException(Parcel.java:2340)
W/KeyStore( 2975):  at android.os.Parcel.readException(Parcel.java:2282)
W/KeyStore( 2975):  at android.security.keystore.IKeystoreService$Stub$Proxy.get(IKeystoreService.java:988)
W/KeyStore( 2975):  at android.security.KeyStore.get(KeyStore.java:233)
W/KeyStore( 2975):  at android.security.KeyStore.get(KeyStore.java:222)
W/KeyStore( 2975):  at android.security.keystore.AndroidKeyStoreSpi.engineGetCertificate(AndroidKeyStoreSpi.java:165)
W/KeyStore( 2975):  at java.security.KeyStore.getCertificate(KeyStore.java:1120)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.ciphers.RSACipher18Implementation.getPublicKey(RSACipher18Implementation.java:90)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.ciphers.RSACipher18Implementation.wrap(RSACipher18Implementation.java:39)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.ciphers.StorageCipher18Implementation.<init>(StorageCipher18Implementation.java:52)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.ensureInitialized(FlutterSecureStoragePlugin.java:95)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.access$100(FlutterSecureStoragePlugin.java:37)
W/KeyStore( 2975):  at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin$MethodRunner.run(FlutterSecureStoragePlugin.java:284)
W/KeyStore( 2975):  at android.os.Handler.handleCallback(Handler.java:938)
W/KeyStore( 2975):  at android.os.Handler.dispatchMessage(Handler.java:99)
W/KeyStore( 2975):  at android.os.Looper.loop(Looper.java:223)
W/KeyStore( 2975):  at android.os.HandlerThread.run(HandlerThread.java:67)
E/FlutterSecureStoragePl( 2975): StorageCipher initialization failed
E/FlutterSecureStoragePl( 2975): java.lang.Exception: No certificate found under alias: com.example.applielikya.FlutterSecureStoragePluginKey
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.ciphers.RSACipher18Implementation.getPublicKey(RSACipher18Implementation.java:92)
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.ciphers.RSACipher18Implementation.wrap(RSACipher18Implementation.java:39)
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.ciphers.StorageCipher18Implementation.<init>(StorageCipher18Implementation.java:52)
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.ensureInitialized(FlutterSecureStoragePlugin.java:95)
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin.access$100(FlutterSecureStoragePlugin.java:37)
E/FlutterSecureStoragePl( 2975):    at com.it_nomads.fluttersecurestorage.FlutterSecureStoragePlugin$MethodRunner.run(FlutterSecureStoragePlugin.java:284)
E/FlutterSecureStoragePl( 2975):    at android.os.Handler.handleCallback(Handler.java:938)
E/FlutterSecureStoragePl( 2975):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/FlutterSecureStoragePl( 2975):    at android.os.Looper.loop(Looper.java:223)
E/FlutterSecureStoragePl( 2975):    at android.os.HandlerThread.run(HandlerThread.java:67)

I don't know if it could be related, but I have min Sdk 19 in my code, due to some packages needing this version.

I need this to start both my physical device and an emulator on Vscode with two different accounts in my app (an admin and an user) to check the transmission of notifications from one to another, if another way to achieve that exists I'd also be up to know.

This is the code :

import 'package:applielikya/models/login_response.dart';
import 'package:applielikya/models/user.dart';
import 'package:applielikya/services/auth/login.dart';
import 'package:applielikya/views/homepage.dart';
import 'package:applielikya/widgets/createRoute.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  State<LoginPage> createState() => LoginPageState();
}

enum ButtonState { init, loading, done }

class LoginPageState extends State<LoginPage> {
  final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
  final FlutterSecureStorage storage = const FlutterSecureStorage();
  ButtonState _state = ButtonState.init;
  bool _passwordVisible = false;
  final TextEditingController _usernameController = TextEditingController(text: "kentay");
  final TextEditingController _passwordController = TextEditingController(text: "kentay");
  bool _isAuth = false;
  String _responseMessage = "";

  void saveToken(SuccessResponse response) async {
    await storage.write(key: "accessToken", value: response.accessToken);
    await storage.write(key: "refreshToken", value: response.refreshToken);
  }

  void saveUser(UserResponse user) async {
    final SharedPreferences prefs = await _prefs;
    prefs.setString('username', user.username as String);
    prefs.setInt('id', user.id as int);
    prefs.setString('role', user.role as String);
    if (user.role == "prof") {
      prefs.setString("firstname", user.firstname!);
      prefs.setString("lastname", user.lastname!);
      prefs.setString("email", user.email!);
    }
  }

  submitLogin() async {
    setState(() => _state = ButtonState.loading);
    final response = await login(
      UserRequest(username : _usernameController.text, password: _passwordController.text)
    );

    setState(() {
      _isAuth = response.auth;
      _state = ButtonState.done;
    });

    if (response is SuccessResponse) {
      saveToken(response);
      saveUser(response.user);
      setState(() => _state = ButtonState.init);
      Navigator.of(context).push(
        createRoute(
          const MyHomePage(),
          const Offset(0.0, 1.0),
          Offset.zero,
          Curves.easeInCirc
        )
      );
    } else {
      if (response is ErrorResponse) {
        setState(() => _responseMessage = response.message);
      }
    }
  }
2

There are 2 best solutions below

0
On BEST ANSWER

In case it helps someone, I fixed it by clearing datas and cache of the app on my emulator in the parameters of the device.

1
On

i think the isseus was form arecent update. just add the option below for android.

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