11import 'dart:convert' ;
22import 'dart:io' ;
3+ import 'dart:math' ;
4+ import 'dart:typed_data' ;
35
4- import 'package:cryptography/cryptography.dart' ;
56import 'package:objectbox_generator/src/analysis/analysis.dart' ;
67import 'package:objectbox_generator/src/analysis/build_properties.dart' ;
8+ import 'package:pointycastle/api.dart' ;
9+ import 'package:pointycastle/macs/poly1305.dart' ;
10+ import 'package:pointycastle/stream/chacha20poly1305.dart' ;
11+ import 'package:pointycastle/stream/chacha7539.dart' ;
712import 'package:pub_semver/pub_semver.dart' ;
813import 'package:pubspec_parse/pubspec_parse.dart' ;
914import 'package:test/expect.dart' ;
@@ -16,14 +21,14 @@ void main() {
1621 test ("obfuscate token" , () async {
1722 final token = "REPLACE_WITH_TOKEN" ;
1823
19- var obfuscatedToken = await obfuscateToken (token);
20- final secretKeyBase64 = obfuscatedToken.secretKeyBase64 ;
21- final secretTextBase64 = obfuscatedToken.secretTextBase64 ;
24+ var obfuscatedToken = _obfuscateToken (token);
25+ final keyBase64 = obfuscatedToken.keyBase64 ;
26+ final dataBase64 = obfuscatedToken.dataBase64 ;
2227 print ("Store this in generator/lib/${ObjectBoxAnalysis .tokenFilePath }:" );
23- print ("$secretKeyBase64 \n $secretTextBase64 " );
28+ print ("$keyBase64 \n $dataBase64 " );
2429
25- final decryptedToken = await ObjectBoxAnalysis ()
26- . decryptToken (secretKeyBase64, secretTextBase64 );
30+ final decryptedToken =
31+ ObjectBoxAnalysis (). decryptAndVerifyToken (keyBase64, dataBase64 );
2732 expect (decryptedToken, equals (token));
2833 }, skip: true );
2934
@@ -35,10 +40,10 @@ void main() {
3540 markTestSkipped ("DART_ANALYSIS_TOKEN not set" );
3641 return ;
3742 }
38- var obfuscatedToken = await obfuscateToken (token);
43+ var obfuscatedToken = _obfuscateToken (token);
3944 final tokenFile = File ("lib/${ObjectBoxAnalysis .tokenFilePath }" );
4045 await tokenFile.writeAsString (
41- "${obfuscatedToken .secretKeyBase64 }\n ${obfuscatedToken .secretTextBase64 }" );
46+ "${obfuscatedToken .keyBase64 }\n ${obfuscatedToken .dataBase64 }" );
4247
4348 final testPubspec = Pubspec ("test" , dependencies: {
4449 "flutter" : SdkDependency ("flutter" ),
@@ -117,22 +122,36 @@ void main() {
117122 });
118123}
119124
120- class ObfuscatedToken {
121- final String secretTextBase64;
122- final String secretKeyBase64;
123-
124- ObfuscatedToken (this .secretTextBase64, this .secretKeyBase64);
125+ /// Encrypt to obfuscate token and use MAC to ensure token did not get damaged.
126+ /// This is explicitly not used for security purposes.
127+ ObfuscatedToken _obfuscateToken (String token) {
128+ // Note: support Dart before 3.2 where encode returns List<int>
129+ final message = Uint8List .fromList (utf8.encode (token));
130+ final key = _generateRandomBytes (32 );
131+ final nonce = _generateRandomBytes (ObfuscatedToken .nonceLengthBytes);
132+
133+ final algorithm = ChaCha20Poly1305 (ChaCha7539Engine (), Poly1305 ());
134+ var params = AEADParameters (
135+ KeyParameter (key), ObfuscatedToken .macLengthBits, nonce, Uint8List (0 ));
136+ algorithm.init (true /* encrypt */ , params);
137+
138+ final encrypted = Uint8List (algorithm.getOutputSize (message.length));
139+ final outLen =
140+ algorithm.processBytes (message, 0 , message.length, encrypted, 0 );
141+ algorithm.doFinal (encrypted, outLen);
142+
143+ // Store nonce together with encrypted text (which includes the MAC at the end)
144+ final dataBase64 = base64Encode (nonce + encrypted);
145+ final keyBase64 = base64Encode (key);
146+
147+ return ObfuscatedToken (dataBase64, keyBase64);
125148}
126149
127- Future <ObfuscatedToken > obfuscateToken (String token) async {
128- final algorithm = Chacha20 .poly1305Aead ();
129- var secretKey = await algorithm.newSecretKey ();
130-
131- final message = utf8.encode (token);
132- final secretBox = await algorithm.encrypt (message, secretKey: secretKey);
133-
134- final secretTextBase64 = base64Encode (secretBox.concatenation ());
135- final secretKeyBase64 = base64Encode (await secretKey.extractBytes ());
136-
137- return ObfuscatedToken (secretTextBase64, secretKeyBase64);
150+ Uint8List _generateRandomBytes (int length) {
151+ final random = Random .secure ();
152+ final bytes = Uint8List (length);
153+ for (int i = 0 ; i < length; i++ ) {
154+ bytes[i] = random.nextInt (256 );
155+ }
156+ return bytes;
138157}
0 commit comments