tekartik / sembast.dart

Simple io database
BSD 2-Clause "Simplified" License
763 stars 63 forks source link

Consider adding async "Codec" for encryption #341

Closed timshadel closed 1 year ago

timshadel commented 1 year ago

Many Flutter encryption libraries use native platform methods for encryption. Because these must use MethodChannel calls, they must be async. The Codec is a wonderful, common interface for synchronous change steps which can be fused together. It doesn't have any asynchronous option.

Sadly, most synchronous encryption available in Dart is inadequate for production use. Either their algorithms are weak, or they implement only some of the algorithms required to construct production-grade encryption, or they cannot secure their memory properly. Sodium is great, and it's synchronous because it uses C APIs called via FFI to an underlying layer which manages secure memory. (See also #340) But it's not for everyone. Anyone requiring FIPS-140 compliance needs to use only approved encryption providers, like OpenSSL or native Apple Crypto or Google's BoringCrypto. These will require async method calls.

I don't know enough about the internals of Sembast to know if using async would drastically affect the rest of the API (often a low-level async call means changing all calling paths to async, and that may be disastrously complex.

All Store operations are already async, as is the openDatabase call. But it's the internals that must be reviewed before taking this idea seriously.

alextekartik commented 1 year ago

Supporting async Codec could be possible but would require a lot of changes and complexity in supporting both models (synchronous and asynchronous). Using encryption could have huge performance penalty (especially on startup as everything is decrypted during open). I understand the encryption support might sound too good compared to what it really is.

I just wonder if its worth the support though, sembast is a small all in memory database. Any serious database needs should rely on more complete packages such as isar, objectbox, hive, realm, sqflite

If not all your information is sensitive, you could also consider using a regular database and only encrypt the data your need.

(I'm assuming you're looking at other alternatives. If indeed you think you don't have other solutions than sembast - and you seem to have to lot of knowledge - I could consider adding a new asynchronous codec interface)

alextekartik commented 1 year ago

Following your request async codec support has been added in sembast 3.4.2 just published.

Create an asynchronous codec

The codec must be able to handle the conversion of a json encodable data to a single line string. (i.e. json being one). If your codec requires calling a plugin or an asynchronous operation you have to create an asynchronous codec. One solution is to subclass AsyncContentCodecBase (which is a Codec<Object?, String> but with the synchronous encoding/decoding disabled) where you just have to implement:


/// My simple asynchronous codec.
class MyAsyncCodec extends AsyncContentCodecBase {
  String _reverseString(String text) => text.split('').reversed.join();

  @override
  Future<Object?> decodeAsync(String encoded) async {
    // Simple demo, just reverse the json asynchronously.
    return jsonDecode(_reverseString(encoded));
  }

  @override
  Future<String> encodeAsync(Object? input) async {
    // Simple demo, just reverse the json asynchronously.
    return _reverseString(jsonEncode(input));
  }
}