@@ -60,21 +60,22 @@ class EncryptionService {
6060 }
6161
6262 /// Encrypt a message (text or file bytes)
63- Future <Map <String , dynamic >> encrypt (Uint8List plainBytes) async {
63+ Future <Map <String , dynamic >> encrypt (Uint8List plainBytes,
64+ {bool inNewThread = false }) async {
6465 if (_sharedAesKey == null ) throw Exception ('AES key not derived' );
6566
6667 final aes = AesGcm .with256bits ();
6768
68- // Future<SecretBox> encryptInIsolate() async {
69- // return await aes.encrypt(
70- // plainBytes,
71- // secretKey: _sharedAesKey!,
72- // );
73- // }
74-
75- final encrypted = await aes.encrypt (
69+ Future <SecretBox > encryptInIsolate () async {
70+ return await aes.encrypt (
7671 plainBytes,
77- secretKey: _sharedAesKey! );
72+ secretKey: _sharedAesKey! ,
73+ );
74+ }
75+
76+ final encrypted = inNewThread
77+ ? await Isolate .run (() => encryptInIsolate ())
78+ : await aes.encrypt (plainBytes, secretKey: _sharedAesKey! );
7879
7980 return {
8081 'nonce' : base64Encode (encrypted.nonce),
@@ -85,79 +86,81 @@ class EncryptionService {
8586
8687 /// Encrypt a stream message (text or file bytes) and return a stream of encrypted bytes.
8788 /// The returned stream emits the encrypted bytes as they become available.
88- /// The nonce and mac are returned alongside the stream for decryption .
89+ /// The nonce is returned immediately, and the MAC is provided via the [onMac] callback when available .
8990 ///
9091 /// Usage:
91- /// final result = await encryptStream(plainBytes);
92- /// result['stream'] is the Stream`<List<int>>` of encrypted bytes.
93- /// result['nonce'] and result['mac'] are base64 strings.
94- Future <Map <String , dynamic >> encryptStream (
95- Stream <List <int >> plainBytes) async {
92+ /// final stream = encryptStream(
93+ /// plainBytes,
94+ /// onMac: (mac, nonce) {
95+ /// // Use mac and nonce when available
96+ /// },
97+ /// );
98+ /// // stream is Stream`<List<int>>`
99+ Stream <List <int >> encryptStream (
100+ Stream <List <int >> plainBytes, {
101+ required void Function (String mac, String nonce) onMac,
102+ }) {
96103 if (_sharedAesKey == null ) throw Exception ('AES key not derived' );
97104
98105 final aes = AesGcm .with256bits ();
99106 final nonce = aes.newNonce ();
100107
101- // Prepare a controller to output the encrypted bytes
102- final controller = StreamController <List <int >>();
103- Mac ? mac;
104-
105- // Start encryption
106108 final secretBoxStream = aes.encryptStream (
107109 plainBytes,
108110 secretKey: _sharedAesKey! ,
109111 nonce: nonce,
110112 onMac: (Mac m) {
111- mac = m ;
113+ onMac ( base64Encode (m.bytes), base64Encode (nonce)) ;
112114 },
113115 );
114116
115- // Listen to the SecretBox stream and add cipherText chunks to the output stream
116- secretBoxStream. listen (
117- (secretBox) {
118- controller. add (secretBox);
119- },
120- onError : controller.addError,
121- onDone : () async {
122- await controller. close ();
123- } ,
124- cancelOnError : true ,
125- );
117+ // The stream emits List<int> ( cipherText chunks)
118+ return secretBoxStream;
119+ }
120+
121+ /// Decrypt a received message
122+ Future < List < int >> decrypt (
123+ { required String nonce,
124+ required List < int > cipherText,
125+ required String mac ,
126+ bool isNewThread = false }) async {
127+ if (_sharedAesKey == null ) throw Exception ( 'AES key not derived' );
126128
127- // Wait for the first chunk to ensure the stream is valid
128- await controller.done;
129+ final aes = AesGcm .with256bits ();
130+ final box = SecretBox (
131+ cipherText,
132+ nonce: base64Decode (nonce),
133+ mac: Mac (base64Decode (mac)),
134+ );
129135
130- if (mac == null ) {
131- throw Exception ( 'Encryption failed: MAC not generated' );
136+ Future < List < int >> decryptInIsolate () async {
137+ return await aes. decrypt (box, secretKey : _sharedAesKey ! );
132138 }
133139
134- return {
135- 'nonce' : base64Encode (nonce),
136- 'mac' : base64Encode (mac! .bytes),
137- 'stream' : controller.stream,
138- };
140+ return isNewThread
141+ ? await Isolate .run (() => decryptInIsolate ())
142+ : await aes.decrypt (box, secretKey: _sharedAesKey! );
139143 }
140144
141- /// Decrypt a received message
142- Future <List <int >> decrypt ({
145+ /// Decrypts a stream of encrypted data chunks (cipherText) using the current shared AES key.
146+ ///
147+ /// [cipherTextStream] is a stream of encrypted bytes (cipherText).
148+ /// [nonce] and [mac] are required for decryption and should be provided as base64 strings.
149+ /// Returns a stream of decrypted bytes.
150+ Stream <List <int >> decryptStream ({
151+ required Stream <List <int >> cipherTextStream,
143152 required String nonce,
144- required List <int > cipherText,
145153 required String mac,
146- }) async {
154+ }) {
147155 if (_sharedAesKey == null ) throw Exception ('AES key not derived' );
148156
149157 final aes = AesGcm .with256bits ();
150- final box = SecretBox (
151- cipherText,
158+ return aes.decryptStream (
159+ cipherTextStream,
160+ secretKey: _sharedAesKey! ,
152161 nonce: base64Decode (nonce),
153162 mac: Mac (base64Decode (mac)),
154163 );
155-
156- // Future<List<int>> decryptInIsolate() async {
157- // return await aes.decrypt(box, secretKey: _sharedAesKey!);
158- // }
159-
160- return await aes.decrypt (box, secretKey: _sharedAesKey! );
161164 }
162165
163166 /// Reset state (for testing or re-handshake)
0 commit comments