Skip to content

Commit 2ac2d62

Browse files
authored
Refactorings (#48)
* Regenerated ffi bindings * Fix lints * Use more _Scope * Cleanup TODO * Smarter stream buffering logic * Remove unnecessary checkNotNull * Use BytesBuilder * Add another TODO * Migrate to _Scope.sync/async/stream * More use of _Scope
1 parent 558bbab commit 2ac2d62

37 files changed

+212
-464
lines changed

lib/src/impl_ffi/impl_ffi.aes_common.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
part of impl_ffi;
1616

1717
Uint8List _aesImportRawKey(List<int> keyData) {
18-
ArgumentError.checkNotNull(keyData, 'keyData');
1918
if (keyData.length == 24) {
2019
// 192-bit AES is intentionally unsupported, see https://crbug.com/533699
2120
// If not supported in Chrome, there is not reason to support it in Dart.
@@ -31,8 +30,6 @@ Uint8List _aesImportJwkKey(
3130
Map<String, dynamic> jwk, {
3231
required String expectedJwkAlgSuffix,
3332
}) {
34-
ArgumentError.checkNotNull(jwk, 'jwk');
35-
3633
final k = JsonWebKey.fromJson(jwk);
3734

3835
void checkJwk(bool condition, String prop, String message) =>
@@ -79,7 +76,6 @@ Map<String, dynamic> _aesExportJwkKey(
7976
}
8077

8178
Uint8List _aesGenerateKey(int length) {
82-
ArgumentError.checkNotNull(length, 'length');
8379
if (length == 192) {
8480
// 192-bit AES is intentionally unsupported, see https://crbug.com/533699
8581
// If not supported in Chrome, there is not reason to support it in Dart.

lib/src/impl_ffi/impl_ffi.aescbc.dart

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ Stream<Uint8List> _aesCbcEncryptOrDecrypt(
3535
bool encrypt,
3636
Stream<List<int>> source,
3737
List<int> iv,
38-
) async* {
39-
final scope = _Scope();
40-
try {
38+
) {
39+
return _Scope.stream((scope) async* {
4140
assert(key.length == 16 || key.length == 32);
4241
final cipher =
4342
key.length == 16 ? ssl.EVP_aes_128_cbc() : ssl.EVP_aes_256_cbc();
@@ -91,42 +90,28 @@ Stream<Uint8List> _aesCbcEncryptOrDecrypt(
9190
if (outLen.value > 0) {
9291
yield outData.sublist(0, outLen.value);
9392
}
94-
} finally {
95-
scope.release();
96-
}
93+
});
9794
}
9895

9996
class _AesCbcSecretKey implements AesCbcSecretKey {
10097
final Uint8List _key;
10198
_AesCbcSecretKey(this._key);
10299

103100
@override
104-
Future<Uint8List> decryptBytes(List<int> data, List<int> iv) async {
105-
ArgumentError.checkNotNull(data, 'data');
106-
ArgumentError.checkNotNull(iv, 'iv');
107-
return await _bufferStream(decryptStream(Stream.value(data), iv));
108-
}
101+
Future<Uint8List> decryptBytes(List<int> data, List<int> iv) async =>
102+
await _bufferStream(decryptStream(Stream.value(data), iv));
109103

110104
@override
111-
Stream<Uint8List> decryptStream(Stream<List<int>> data, List<int> iv) {
112-
ArgumentError.checkNotNull(data, 'data');
113-
ArgumentError.checkNotNull(iv, 'iv');
114-
return _aesCbcEncryptOrDecrypt(_key, false, data, iv);
115-
}
105+
Stream<Uint8List> decryptStream(Stream<List<int>> data, List<int> iv) =>
106+
_aesCbcEncryptOrDecrypt(_key, false, data, iv);
116107

117108
@override
118-
Future<Uint8List> encryptBytes(List<int> data, List<int> iv) async {
119-
ArgumentError.checkNotNull(data, 'data');
120-
ArgumentError.checkNotNull(iv, 'iv');
121-
return await _bufferStream(encryptStream(Stream.value(data), iv));
122-
}
109+
Future<Uint8List> encryptBytes(List<int> data, List<int> iv) async =>
110+
await _bufferStream(encryptStream(Stream.value(data), iv));
123111

124112
@override
125-
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> iv) {
126-
ArgumentError.checkNotNull(data, 'data');
127-
ArgumentError.checkNotNull(iv, 'iv');
128-
return _aesCbcEncryptOrDecrypt(_key, true, data, iv);
129-
}
113+
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> iv) =>
114+
_aesCbcEncryptOrDecrypt(_key, true, data, iv);
130115

131116
@override
132117
Future<Map<String, dynamic>> exportJsonWebKey() async =>

lib/src/impl_ffi/impl_ffi.aesctr.dart

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,11 @@ Stream<Uint8List> _aesCtrEncryptOrDecrypt(
5858
Stream<List<int>> source,
5959
List<int> counter,
6060
int length,
61-
) async* {
61+
) {
6262
// Heavily inspired by Chromium Web Crypto implementation, see:
6363
// https://chromium.googlesource.com/chromium/src/+/43d62c50b705f88c67b14539e91fd8fd017f70c4/components/webcrypto/algorithms/aes_ctr.cc#144
6464

65-
final scope = _Scope();
66-
try {
65+
return _Scope.stream((scope) async* {
6766
assert(counter.length == 16);
6867
assert(key.length == 16 || key.length == 32);
6968
final cipher =
@@ -198,9 +197,7 @@ Stream<Uint8List> _aesCtrEncryptOrDecrypt(
198197
if (outLen.value > 0) {
199198
yield outData.sublist(0, outLen.value);
200199
}
201-
} finally {
202-
scope.release();
203-
}
200+
});
204201
}
205202

206203
class _AesCtrSecretKey implements AesCtrSecretKey {
@@ -211,8 +208,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
211208
List<int> counter,
212209
int length,
213210
) {
214-
ArgumentError.checkNotNull(counter, 'counter');
215-
ArgumentError.checkNotNull(length, 'length');
216211
if (counter.length != 16) {
217212
throw ArgumentError.value(counter, 'counter', 'must be 16 bytes');
218213
}
@@ -227,7 +222,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
227222
List<int> counter,
228223
int length,
229224
) async {
230-
ArgumentError.checkNotNull(data, 'data');
231225
_checkArguments(counter, length);
232226
return await _bufferStream(decryptStream(
233227
Stream.value(data),
@@ -242,7 +236,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
242236
List<int> counter,
243237
int length,
244238
) {
245-
ArgumentError.checkNotNull(data, 'data');
246239
_checkArguments(counter, length);
247240
return _aesCtrEncryptOrDecrypt(_key, false, data, counter, length);
248241
}
@@ -253,7 +246,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
253246
List<int> counter,
254247
int length,
255248
) async {
256-
ArgumentError.checkNotNull(data, 'data');
257249
_checkArguments(counter, length);
258250
return await _bufferStream(encryptStream(
259251
Stream.value(data),
@@ -268,7 +260,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
268260
List<int> counter,
269261
int length,
270262
) {
271-
ArgumentError.checkNotNull(data, 'data');
272263
_checkArguments(counter, length);
273264
return _aesCtrEncryptOrDecrypt(_key, true, data, counter, length);
274265
}

lib/src/impl_ffi/impl_ffi.aesgcm.dart

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ Future<Uint8List> _aesGcmEncryptDecrypt(
5858
// what chrome does, how firefox passes tests. And check if other
5959
// primitives that accept an iv/nonce has size limitations on it.
6060

61-
final scope = _Scope();
62-
try {
61+
return _Scope.async((scope) async {
6362
assert(key.length == 16 || key.length == 32);
6463
final aead = key.length == 16
6564
? ssl.EVP_aead_aes_128_gcm()
@@ -78,40 +77,38 @@ Future<Uint8List> _aesGcmEncryptDecrypt(
7877
if (isEncrypt) {
7978
final outLen = scope<ffi.Size>();
8079
final maxOut = data.length + ssl.EVP_AEAD_max_overhead(aead);
81-
return _withOutPointer(maxOut, (ffi.Pointer<ffi.Uint8> out) {
82-
_checkOpIsOne(ssl.EVP_AEAD_CTX_seal(
83-
ctx,
84-
out,
85-
outLen,
86-
maxOut,
87-
scope.dataAsPointer(iv),
88-
iv.length,
89-
scope.dataAsPointer(data),
90-
data.length,
91-
scope.dataAsPointer(additionalData_),
92-
additionalData_.length,
93-
));
94-
}).sublist(0, outLen.value);
80+
final out = scope<ffi.Uint8>(maxOut);
81+
_checkOpIsOne(ssl.EVP_AEAD_CTX_seal(
82+
ctx,
83+
out,
84+
outLen,
85+
maxOut,
86+
scope.dataAsPointer(iv),
87+
iv.length,
88+
scope.dataAsPointer(data),
89+
data.length,
90+
scope.dataAsPointer(additionalData_),
91+
additionalData_.length,
92+
));
93+
return out.copy(outLen.value);
9594
} else {
9695
final outLen = scope<ffi.Size>();
97-
return _withOutPointer(data.length, (ffi.Pointer<ffi.Uint8> out) {
98-
_checkOpIsOne(ssl.EVP_AEAD_CTX_open(
99-
ctx,
100-
out,
101-
outLen,
102-
data.length,
103-
scope.dataAsPointer(iv),
104-
iv.length,
105-
scope.dataAsPointer(data),
106-
data.length,
107-
scope.dataAsPointer(additionalData_),
108-
additionalData_.length,
109-
));
110-
}).sublist(0, outLen.value);
96+
final out = scope<ffi.Uint8>(data.length);
97+
_checkOpIsOne(ssl.EVP_AEAD_CTX_open(
98+
ctx,
99+
out,
100+
outLen,
101+
data.length,
102+
scope.dataAsPointer(iv),
103+
iv.length,
104+
scope.dataAsPointer(data),
105+
data.length,
106+
scope.dataAsPointer(additionalData_),
107+
additionalData_.length,
108+
));
109+
return out.copy(outLen.value);
111110
}
112-
} finally {
113-
scope.release();
114-
}
111+
});
115112
}
116113

117114
class _AesGcmSecretKey implements AesGcmSecretKey {

lib/src/impl_ffi/impl_ffi.digest.dart

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ abstract class _Hash implements Hash {
1818
const _Hash();
1919

2020
factory _Hash.fromHash(Hash hash) {
21-
ArgumentError.checkNotNull(hash, 'hash');
22-
2321
if (hash is _Hash) {
2422
return hash;
2523
}
@@ -41,24 +39,27 @@ abstract class _Hash implements Hash {
4139
}
4240

4341
@override
44-
Future<Uint8List> digestBytes(List<int> data) {
45-
ArgumentError.checkNotNull(data, 'data');
46-
47-
return digestStream(Stream.value(data));
48-
}
42+
Future<Uint8List> digestBytes(List<int> data) =>
43+
digestStream(Stream.value(data));
4944

5045
@override
51-
Future<Uint8List> digestStream(Stream<List<int>> data) async {
52-
ArgumentError.checkNotNull(data, 'data');
53-
54-
return await _withEVP_MD_CTX((ctx) async {
46+
Future<Uint8List> digestStream(Stream<List<int>> data) {
47+
return _Scope.async((scope) async {
48+
final ctx = scope.create(ssl.EVP_MD_CTX_new, ssl.EVP_MD_CTX_free);
49+
// Initialize with hash function
5550
_checkOp(ssl.EVP_DigestInit(ctx, _md) == 1);
51+
52+
// Stream data
5653
await _streamToUpdate(data, ctx, ssl.EVP_DigestUpdate);
54+
55+
// Get size of the output buffer
5756
final size = ssl.EVP_MD_CTX_size(ctx);
58-
_checkOp(size > 0);
59-
return _withOutPointer(size, (ffi.Pointer<ffi.Uint8> p) {
60-
_checkOp(ssl.EVP_DigestFinal(ctx, p, ffi.nullptr) == 1);
61-
});
57+
_checkOp(size > 0); // sanity check
58+
59+
// Allocate output buffer and return output
60+
final out = scope<ffi.Uint8>(size);
61+
_checkOp(ssl.EVP_DigestFinal(ctx, out, ffi.nullptr) == 1);
62+
return out.copy(size);
6263
});
6364
}
6465
}

0 commit comments

Comments
 (0)