1
1
import 'dart:convert' ;
2
2
import 'dart:io' ;
3
+ import 'dart:math' ;
4
+ import 'dart:typed_data' ;
3
5
4
- import 'package:cryptography/cryptography.dart' ;
5
6
import 'package:objectbox_generator/src/analysis/analysis.dart' ;
6
7
import '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' ;
7
12
import 'package:pub_semver/pub_semver.dart' ;
8
13
import 'package:pubspec_parse/pubspec_parse.dart' ;
9
14
import 'package:test/expect.dart' ;
@@ -16,14 +21,14 @@ void main() {
16
21
test ("obfuscate token" , () async {
17
22
final token = "REPLACE_WITH_TOKEN" ;
18
23
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 ;
22
27
print ("Store this in generator/lib/${ObjectBoxAnalysis .tokenFilePath }:" );
23
- print ("$secretKeyBase64 \n $secretTextBase64 " );
28
+ print ("$keyBase64 \n $dataBase64 " );
24
29
25
- final decryptedToken = await ObjectBoxAnalysis ()
26
- . decryptToken (secretKeyBase64, secretTextBase64 );
30
+ final decryptedToken =
31
+ ObjectBoxAnalysis (). decryptAndVerifyToken (keyBase64, dataBase64 );
27
32
expect (decryptedToken, equals (token));
28
33
}, skip: true );
29
34
@@ -35,10 +40,10 @@ void main() {
35
40
markTestSkipped ("DART_ANALYSIS_TOKEN not set" );
36
41
return ;
37
42
}
38
- var obfuscatedToken = await obfuscateToken (token);
43
+ var obfuscatedToken = _obfuscateToken (token);
39
44
final tokenFile = File ("lib/${ObjectBoxAnalysis .tokenFilePath }" );
40
45
await tokenFile.writeAsString (
41
- "${obfuscatedToken .secretKeyBase64 }\n ${obfuscatedToken .secretTextBase64 }" );
46
+ "${obfuscatedToken .keyBase64 }\n ${obfuscatedToken .dataBase64 }" );
42
47
43
48
final testPubspec = Pubspec ("test" , dependencies: {
44
49
"flutter" : SdkDependency ("flutter" ),
@@ -117,22 +122,36 @@ void main() {
117
122
});
118
123
}
119
124
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);
125
148
}
126
149
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;
138
157
}
0 commit comments