Skip to content

Commit

Permalink
Refactorings (#48)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jonasfj authored Oct 18, 2022
1 parent 558bbab commit 2ac2d62
Show file tree
Hide file tree
Showing 37 changed files with 212 additions and 464 deletions.
4 changes: 0 additions & 4 deletions lib/src/impl_ffi/impl_ffi.aes_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
part of impl_ffi;

Uint8List _aesImportRawKey(List<int> keyData) {
ArgumentError.checkNotNull(keyData, 'keyData');
if (keyData.length == 24) {
// 192-bit AES is intentionally unsupported, see https://crbug.com/533699
// If not supported in Chrome, there is not reason to support it in Dart.
Expand All @@ -31,8 +30,6 @@ Uint8List _aesImportJwkKey(
Map<String, dynamic> jwk, {
required String expectedJwkAlgSuffix,
}) {
ArgumentError.checkNotNull(jwk, 'jwk');

final k = JsonWebKey.fromJson(jwk);

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

Uint8List _aesGenerateKey(int length) {
ArgumentError.checkNotNull(length, 'length');
if (length == 192) {
// 192-bit AES is intentionally unsupported, see https://crbug.com/533699
// If not supported in Chrome, there is not reason to support it in Dart.
Expand Down
37 changes: 11 additions & 26 deletions lib/src/impl_ffi/impl_ffi.aescbc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ Stream<Uint8List> _aesCbcEncryptOrDecrypt(
bool encrypt,
Stream<List<int>> source,
List<int> iv,
) async* {
final scope = _Scope();
try {
) {
return _Scope.stream((scope) async* {
assert(key.length == 16 || key.length == 32);
final cipher =
key.length == 16 ? ssl.EVP_aes_128_cbc() : ssl.EVP_aes_256_cbc();
Expand Down Expand Up @@ -91,42 +90,28 @@ Stream<Uint8List> _aesCbcEncryptOrDecrypt(
if (outLen.value > 0) {
yield outData.sublist(0, outLen.value);
}
} finally {
scope.release();
}
});
}

class _AesCbcSecretKey implements AesCbcSecretKey {
final Uint8List _key;
_AesCbcSecretKey(this._key);

@override
Future<Uint8List> decryptBytes(List<int> data, List<int> iv) async {
ArgumentError.checkNotNull(data, 'data');
ArgumentError.checkNotNull(iv, 'iv');
return await _bufferStream(decryptStream(Stream.value(data), iv));
}
Future<Uint8List> decryptBytes(List<int> data, List<int> iv) async =>
await _bufferStream(decryptStream(Stream.value(data), iv));

@override
Stream<Uint8List> decryptStream(Stream<List<int>> data, List<int> iv) {
ArgumentError.checkNotNull(data, 'data');
ArgumentError.checkNotNull(iv, 'iv');
return _aesCbcEncryptOrDecrypt(_key, false, data, iv);
}
Stream<Uint8List> decryptStream(Stream<List<int>> data, List<int> iv) =>
_aesCbcEncryptOrDecrypt(_key, false, data, iv);

@override
Future<Uint8List> encryptBytes(List<int> data, List<int> iv) async {
ArgumentError.checkNotNull(data, 'data');
ArgumentError.checkNotNull(iv, 'iv');
return await _bufferStream(encryptStream(Stream.value(data), iv));
}
Future<Uint8List> encryptBytes(List<int> data, List<int> iv) async =>
await _bufferStream(encryptStream(Stream.value(data), iv));

@override
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> iv) {
ArgumentError.checkNotNull(data, 'data');
ArgumentError.checkNotNull(iv, 'iv');
return _aesCbcEncryptOrDecrypt(_key, true, data, iv);
}
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> iv) =>
_aesCbcEncryptOrDecrypt(_key, true, data, iv);

@override
Future<Map<String, dynamic>> exportJsonWebKey() async =>
Expand Down
15 changes: 3 additions & 12 deletions lib/src/impl_ffi/impl_ffi.aesctr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@ Stream<Uint8List> _aesCtrEncryptOrDecrypt(
Stream<List<int>> source,
List<int> counter,
int length,
) async* {
) {
// Heavily inspired by Chromium Web Crypto implementation, see:
// https://chromium.googlesource.com/chromium/src/+/43d62c50b705f88c67b14539e91fd8fd017f70c4/components/webcrypto/algorithms/aes_ctr.cc#144

final scope = _Scope();
try {
return _Scope.stream((scope) async* {
assert(counter.length == 16);
assert(key.length == 16 || key.length == 32);
final cipher =
Expand Down Expand Up @@ -198,9 +197,7 @@ Stream<Uint8List> _aesCtrEncryptOrDecrypt(
if (outLen.value > 0) {
yield outData.sublist(0, outLen.value);
}
} finally {
scope.release();
}
});
}

class _AesCtrSecretKey implements AesCtrSecretKey {
Expand All @@ -211,8 +208,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
List<int> counter,
int length,
) {
ArgumentError.checkNotNull(counter, 'counter');
ArgumentError.checkNotNull(length, 'length');
if (counter.length != 16) {
throw ArgumentError.value(counter, 'counter', 'must be 16 bytes');
}
Expand All @@ -227,7 +222,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
List<int> counter,
int length,
) async {
ArgumentError.checkNotNull(data, 'data');
_checkArguments(counter, length);
return await _bufferStream(decryptStream(
Stream.value(data),
Expand All @@ -242,7 +236,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
List<int> counter,
int length,
) {
ArgumentError.checkNotNull(data, 'data');
_checkArguments(counter, length);
return _aesCtrEncryptOrDecrypt(_key, false, data, counter, length);
}
Expand All @@ -253,7 +246,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
List<int> counter,
int length,
) async {
ArgumentError.checkNotNull(data, 'data');
_checkArguments(counter, length);
return await _bufferStream(encryptStream(
Stream.value(data),
Expand All @@ -268,7 +260,6 @@ class _AesCtrSecretKey implements AesCtrSecretKey {
List<int> counter,
int length,
) {
ArgumentError.checkNotNull(data, 'data');
_checkArguments(counter, length);
return _aesCtrEncryptOrDecrypt(_key, true, data, counter, length);
}
Expand Down
63 changes: 30 additions & 33 deletions lib/src/impl_ffi/impl_ffi.aesgcm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ Future<Uint8List> _aesGcmEncryptDecrypt(
// what chrome does, how firefox passes tests. And check if other
// primitives that accept an iv/nonce has size limitations on it.

final scope = _Scope();
try {
return _Scope.async((scope) async {
assert(key.length == 16 || key.length == 32);
final aead = key.length == 16
? ssl.EVP_aead_aes_128_gcm()
Expand All @@ -78,40 +77,38 @@ Future<Uint8List> _aesGcmEncryptDecrypt(
if (isEncrypt) {
final outLen = scope<ffi.Size>();
final maxOut = data.length + ssl.EVP_AEAD_max_overhead(aead);
return _withOutPointer(maxOut, (ffi.Pointer<ffi.Uint8> out) {
_checkOpIsOne(ssl.EVP_AEAD_CTX_seal(
ctx,
out,
outLen,
maxOut,
scope.dataAsPointer(iv),
iv.length,
scope.dataAsPointer(data),
data.length,
scope.dataAsPointer(additionalData_),
additionalData_.length,
));
}).sublist(0, outLen.value);
final out = scope<ffi.Uint8>(maxOut);
_checkOpIsOne(ssl.EVP_AEAD_CTX_seal(
ctx,
out,
outLen,
maxOut,
scope.dataAsPointer(iv),
iv.length,
scope.dataAsPointer(data),
data.length,
scope.dataAsPointer(additionalData_),
additionalData_.length,
));
return out.copy(outLen.value);
} else {
final outLen = scope<ffi.Size>();
return _withOutPointer(data.length, (ffi.Pointer<ffi.Uint8> out) {
_checkOpIsOne(ssl.EVP_AEAD_CTX_open(
ctx,
out,
outLen,
data.length,
scope.dataAsPointer(iv),
iv.length,
scope.dataAsPointer(data),
data.length,
scope.dataAsPointer(additionalData_),
additionalData_.length,
));
}).sublist(0, outLen.value);
final out = scope<ffi.Uint8>(data.length);
_checkOpIsOne(ssl.EVP_AEAD_CTX_open(
ctx,
out,
outLen,
data.length,
scope.dataAsPointer(iv),
iv.length,
scope.dataAsPointer(data),
data.length,
scope.dataAsPointer(additionalData_),
additionalData_.length,
));
return out.copy(outLen.value);
}
} finally {
scope.release();
}
});
}

class _AesGcmSecretKey implements AesGcmSecretKey {
Expand Down
31 changes: 16 additions & 15 deletions lib/src/impl_ffi/impl_ffi.digest.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ abstract class _Hash implements Hash {
const _Hash();

factory _Hash.fromHash(Hash hash) {
ArgumentError.checkNotNull(hash, 'hash');

if (hash is _Hash) {
return hash;
}
Expand All @@ -41,24 +39,27 @@ abstract class _Hash implements Hash {
}

@override
Future<Uint8List> digestBytes(List<int> data) {
ArgumentError.checkNotNull(data, 'data');

return digestStream(Stream.value(data));
}
Future<Uint8List> digestBytes(List<int> data) =>
digestStream(Stream.value(data));

@override
Future<Uint8List> digestStream(Stream<List<int>> data) async {
ArgumentError.checkNotNull(data, 'data');

return await _withEVP_MD_CTX((ctx) async {
Future<Uint8List> digestStream(Stream<List<int>> data) {
return _Scope.async((scope) async {
final ctx = scope.create(ssl.EVP_MD_CTX_new, ssl.EVP_MD_CTX_free);
// Initialize with hash function
_checkOp(ssl.EVP_DigestInit(ctx, _md) == 1);

// Stream data
await _streamToUpdate(data, ctx, ssl.EVP_DigestUpdate);

// Get size of the output buffer
final size = ssl.EVP_MD_CTX_size(ctx);
_checkOp(size > 0);
return _withOutPointer(size, (ffi.Pointer<ffi.Uint8> p) {
_checkOp(ssl.EVP_DigestFinal(ctx, p, ffi.nullptr) == 1);
});
_checkOp(size > 0); // sanity check

// Allocate output buffer and return output
final out = scope<ffi.Uint8>(size);
_checkOp(ssl.EVP_DigestFinal(ctx, out, ffi.nullptr) == 1);
return out.copy(size);
});
}
}
Expand Down
Loading

0 comments on commit 2ac2d62

Please sign in to comment.