Skip to content

chore: Drop archived 'encrypt' dep, use pointycastle directly#92

Open
MohamedGawdat wants to merge 1 commit intoFlagsmith:mainfrom
MohamedGawdat:chore/drop-encrypt-use-pointycastle
Open

chore: Drop archived 'encrypt' dep, use pointycastle directly#92
MohamedGawdat wants to merge 1 commit intoFlagsmith:mainfrom
MohamedGawdat:chore/drop-encrypt-use-pointycastle

Conversation

@MohamedGawdat
Copy link
Copy Markdown

@MohamedGawdat MohamedGawdat commented Apr 29, 2026

Closes #91.

Why

flagsmith ^6.1.0 depends on encrypt ^5.0.3, which pins pointycastle ^3.7.3. This blocks downstream apps that depend on pointycastle ^4.0.0:

flagsmith ^6.1.0 -> encrypt ^5.0.3 -> pointycastle ^3.7.3
my app                              -> pointycastle ^4.0.0  ❌

Bumping encrypt is not an option — leocavalcante/encrypt is archived (read-only), and PR encrypt#343 (which would have widened its pointycastle constraint) has been open and unreviewed since Feb 2025. encrypt 5.0.4 will remain the final release, permanently locking it to pointycastle ^3.7.3.

What

StorageSecurity (the only consumer of encrypt in this codebase) used encrypt as a thin wrapper around PointyCastle's Salsa20Engine. This PR calls Salsa20Engine directly:

  • Same algorithm (Salsa20)
  • Same key derivation (MD5 of password, 16 bytes)
  • Same 8-byte random IV
  • Same on-disk format: base64(iv) || base64(ciphertext)

Fully backwards-compatible with existing encrypted storage — values written by previous versions decrypt identically.

Diff

# pubspec.yaml
-  encrypt: ^5.0.3
+  pointycastle: ^4.0.0
# lib/src/core/tools/security.dart
-import 'package:encrypt/encrypt.dart';
+import 'package:pointycastle/export.dart';

-late Encrypter _enc;
-StorageSecurity(this.password) {
-  _encryptedPassword = _generateEncryptPassword(password!);
-  _enc = Encrypter(Salsa20(Key(_encryptedPassword)));
-}
+StorageSecurity(this.password) {
+  _encryptedPassword = _generateEncryptPassword(password!);
+}
+
+Uint8List _process(Uint8List input, Uint8List iv) {
+  final engine = Salsa20Engine()
+    ..init(true, ParametersWithIV(KeyParameter(_encryptedPassword), iv));
+  return engine.process(input);
+}

(encrypt/decrypt methods updated to call _process directly with utf8/base64 conversion — same I/O contract.)

Net dependency change

Before After
Direct deps encrypt, crypto pointycastle, crypto
Transitive pointycastle yes (via encrypt) yes (direct)

No new transitive packages added.

The 'encrypt' package (leocavalcante/encrypt) is archived and pinned
to pointycastle ^3.7.3, which permanently locks downstream apps out of
pointycastle ^4.0.0. PR #343 to widen the constraint upstream has been
open without review since Feb 2025 and cannot be merged.

StorageSecurity used encrypt only as a thin wrapper around
PointyCastle's Salsa20Engine. This change calls Salsa20Engine
directly:

- Same algorithm (Salsa20)
- Same key derivation (MD5 of password, 16 bytes)
- Same 8-byte random IV
- Same on-disk format: base64(iv) || base64(ciphertext)

Backwards-compatible with existing encrypted storage.

Verified:
- flutter pub get resolves cleanly with pointycastle ^4.0.0
- flutter analyze: no issues
- flutter test: all 122 tests pass
- StorageSecurity round-trip verified for ASCII, empty, unicode,
  JSON, and 1KB strings

Closes Flagsmith#91
@MohamedGawdat MohamedGawdat requested a review from a team as a code owner April 29, 2026 12:46
@MohamedGawdat MohamedGawdat requested review from kyle-ssg and removed request for a team April 29, 2026 12:46
@MohamedGawdat MohamedGawdat changed the title Drop archived 'encrypt' dep, use pointycastle directly chore: drop archived 'encrypt' dep, use pointycastle directly Apr 29, 2026
@MohamedGawdat MohamedGawdat changed the title chore: drop archived 'encrypt' dep, use pointycastle directly Chore: drop archived 'encrypt' dep, use pointycastle directly Apr 29, 2026
@MohamedGawdat MohamedGawdat changed the title Chore: drop archived 'encrypt' dep, use pointycastle directly chore: Drop archived 'encrypt' dep, use pointycastle directly Apr 29, 2026
@MohamedGawdat
Copy link
Copy Markdown
Author

MohamedGawdat commented Apr 29, 2026

@rolodato when you have a moment — this PR removes the dependency on the archived encrypt package, which permanently blocks downstream apps from adopting pointycastle ^4.0.0. The on-disk encrypted-storage format is unchanged (backwards-compatible) and all 122 existing tests pass. Happy to address any feedback.

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

Successfully merging this pull request may close these issues.

Drop dependency on archived 'encrypt' package (blocks pointycastle ^4.0.0)

1 participant