Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decryption Error - Invalid or corrupted pad block #24

Open
rayliverified opened this issue Nov 15, 2024 · 6 comments
Open

Decryption Error - Invalid or corrupted pad block #24

rayliverified opened this issue Nov 15, 2024 · 6 comments

Comments

@rayliverified
Copy link

rayliverified commented Nov 15, 2024

Have you seen this error before?

It started appearing all of a sudden and now doesn't go away. Locks the app.
Clearing app storage works the first time but on app restart, it appears again.

I/flutter ( 6835): Loon -> PersistManager -> InitOperation started.
I/flutter ( 6835): Loon -> FilePersistor -> Directory: /data/user/0/com.treatmyocd.nocd.qa/app_flutter/loon
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> Hydrate started.
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> Hydrate completed in 8ms.
I/flutter ( 6835): Loon -> PersistManager -> InitOperation completed in 1033ms.
I/flutter ( 6835): Loon -> PersistManager -> HydrateAllOperation started.
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> DataStore:__store__ -> Hydrate started.
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> DataStore:__store__.encrypted -> Hydrate started.
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> DataStore:__store__ -> Hydrate completed in 1ms.
I/flutter ( 6835): Loon -> FilePersistor -> Worker -> DataStore:__store__.encrypted -> Hydrate failed in 94ms.
I/flutter ( 6835): Loon -> FilePersistor -> Request error: Invalid argument(s): Invalid or corrupted pad block
E/flutter ( 6835): [ERROR:flutter/runtime/dart_isolate.cc(1315)] Unhandled exception:
E/flutter ( 6835): Invalid argument(s): Invalid or corrupted pad block
E/flutter ( 6835): #0      PKCS7Padding.padCount (package:pointycastle/paddings/pkcs7.dart:42:7)
E/flutter ( 6835): #1      PaddedBlockCipherImpl.doFinal (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:112:30)
E/flutter ( 6835): #2      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:74:25)
E/flutter ( 6835): #3      AES.decrypt (package:encrypt/src/algorithms/aes.dart:68:22)
E/flutter ( 6835): #4      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:39:10)
E/flutter ( 6835): #5      Encrypter.decrypt (package:encrypt/src/encrypter.dart:50:7)
E/flutter ( 6835): #6      Encrypter.decrypt64 (package:encrypt/src/encrypter.dart:66:12)
E/flutter ( 6835): #7      DataStoreEncrypter.decrypt (package:loon/persistor/data_store_encrypter.dart:50:23)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #8      new FileDataStoreConfig.<anonymous closure> (package:loon/persistor/file_persistor/file_data_store_config.dart:19:29)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #9      Logger.measure (package:loon/utils/logger.dart:65:22)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #10     DataStore.hydrate (package:loon/persistor/data_store.dart:146:9)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #11     Future.wait.<anonymous closure> (dart:async/future.dart:534:21)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #12     DualDataStore.hydrate (package:loon/persistor/data_store.dart:312:5)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #13     Future.wait.<anonymous closure> (dart:async/future.dart:534:21)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #14     DataStoreManager.hydrate.<anonymous closure> (package:loon/persistor/data_store_manager.dart:163:9)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #15     Lock.run (package:loon/persistor/lock.dart:24:22)
E/flutter ( 6835): <asynchronous suspension>
E/flutter ( 6835): #16     PersistorWorker.onMessage (package:loon/persistor/worker/persistor_worker.dart:56:30)
E/flutter ( 6835): <asynchronous suspension>
I/flutter ( 6835): Loon -> PersistManager -> HydrateAllOperation completed in 110ms.
I/flutter ( 6835): Loon -> Error hydrating
E/flutter ( 6835): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: Request error: Invalid argument(s): Invalid or corrupted pad block
@rayliverified
Copy link
Author

Unfortunately, it's not isolated to emulators or Google Play APIs.
Happens every time on a physical device too.

@danReynolds
Copy link
Owner

hey sorry to hear that! I've seen that when the encryption key from secure storage doesn't match the encryption key that was used to save the data. That was just an issue I saw so far on MacOS because secure storage requires a permission outlined here: https://github.com/danReynolds/loon/blob/main/docs/debug.md. That wouldn't be relevant for you on Android obviously though so I'll try and do some encrypted Android testing later today and see if I can repro.

if you uninstall the app and reinstall fresh is it fixed? I'm wondering if maybe a similar issue is happening on Android where secure storage isn't finding a key on next startup. You can debug that here: https://github.com/danReynolds/loon/blob/main/lib/persistor/data_store_encrypter.dart#L28 to check if after encrypting data, on next start it got the same key.

@rayliverified
Copy link
Author

rayliverified commented Nov 15, 2024 via email

@danReynolds
Copy link
Owner

Tried to repro this over the weekend on Android, no luck so far. I see that Flutter secure storage has two options for storing the encryption key on Android. Have you tried the encryptedSharedPreferences option before? Not sure if that's more reliable, seems to be the recommended way in the latest versions.

When you get time to debug, if you could see if the encryption key is not being found on startup here: https://github.com/danReynolds/loon/blob/main/lib/persistor/data_store_encrypter.dart#L28 then that would be a great help. We could narrow down whether it's a flutter_secure_storage issue or some bug in Loon.

@rayliverified
Copy link
Author

Happy holidays Dan!

The conflict with Flutter Secure Storage is likely because I'm using another library that also uses Flutter Secure Storage. So when they are used together, one conflicts with the other.

The same category of issue happens with SharedPreferences as well.

image

Loon and SharedPreferences write to the same IndexDB on Web so they conflict.

Here's a reproducible example:

import 'package:flutter/material.dart';
import 'package:loon/loon.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Loon/SharedPreferences Conflict Demo',
      home: MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _savedValue = 'No Value Saved';
  String _loonStatus = 'Loon Not Initialized';
  late SharedPreferences _prefs;

  // Function to initialize SharedPreferences and Loon
  Future<void> _initializePrefsAndLoon() async {
    setState(() {
      _loonStatus = 'Initializing...';
    });

    try {
      // Initialize SharedPreferences
      _prefs = await SharedPreferences.getInstance();

      // Configure Loon
      Loon.configure(
        persistor:
            Persistor.current(settings: PersistorSettings(encrypted: false)),
      );

      // Attempt to hydrate Loon
      Loon.hydrate();

      setState(() {
        _loonStatus = 'Loon Initialized Successfully';
        _loadSavedValue(); // Load value after Loon initialization
      });
    } catch (e) {
      setState(() {
        _loonStatus = 'Error Initializing Loon: $e';
      });
      print('Error initializing Loon: $e'); // Log the error
    }
  }

  void _loadSavedValue() {
    setState(() {
      _savedValue = _prefs.getString('myKey') ?? 'No Value Saved';
    });
  }

  void _saveValue(String value) async {
    if (_prefs == null) {
      // Handle the case where SharedPreferences might not be initialized
      print(
          "SharedPreferences is not initialized. Please initialize Loon and SharedPreferences first.");
      return;
    }
    await _prefs.setString('myKey', value);
    Loon.collection('test').doc('test').createOrUpdate({'myKey': value});
    _loadSavedValue();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Conflict Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Saved Value: $_savedValue'),
            const SizedBox(height: 20),
            Text('Loon Status: $_loonStatus'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _initializePrefsAndLoon,
              child: const Text('Initialize Loon and SharedPreferences'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => _saveValue('Hello from SharedPreferences!'),
              child: const Text('Save Value'),
            ),
          ],
        ),
      ),
    );
  }
}

Press 'Initialize'. Then 'Save Value' to write a value via Loon and SharedPrefs.
Restart the app via Hot Restart and it will crash when trying to 'Initialize'.

What do you recommend as a solution?

@danReynolds
Copy link
Owner

This is super valuable thanks! I'll take a look soon and make a fix/recommendation. Happy holidays!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants