diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 6dfdbf73..4cb13239 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -64,6 +64,7 @@ jobs: compiler: - vm - dart2js + - dart2wasm steps: - uses: browser-actions/setup-chrome@v2 if: ${{ matrix.compiler != 'vm' }} @@ -79,9 +80,13 @@ jobs: run: dart test --platform vm working-directory: ./${{ matrix.package }} - name: "Test: JS build" - if: ${{ matrix.compiler == 'vm' }} + if: ${{ matrix.compiler == 'dart2js' }} run: dart test --platform chrome --compiler dart2js working-directory: ./${{ matrix.package }} + - name: "Test: WASM build" + if: ${{ matrix.compiler == 'dart2wasm' }} + run: dart test --platform chrome --compiler dart2wasm + working-directory: ./${{ matrix.package }} # # Dart packages: PANA score diff --git a/README.md b/README.md index fc8ca2df..a2bc06d4 100644 --- a/README.md +++ b/README.md @@ -28,4 +28,6 @@ Maintained by [terrier989](https://github.com/terrier989). Licensed under the [A Please share feedback / issue reports in the [issue tracker](https://github.com/dint-dev/cryptography/issues). -Pull requests are welcome. \ No newline at end of file +Pull requests are welcome. + +## Testing \ No newline at end of file diff --git a/cryptography/CHANGELOG.md b/cryptography/CHANGELOG.md index cb0ed6e3..f75dacd3 100644 --- a/cryptography/CHANGELOG.md +++ b/cryptography/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.8.0 +* Adds WASM support. `BrowserCryptography` now uses 'dart:js_interop'. + ## 2.7.0 * Adds a cross-platform of Argon2id, a highly recommended algorithm for password hashing. * Introduces a dependency on "package:ffi" (a package by Google). A memory allocator in the package diff --git a/cryptography/README.md b/cryptography/README.md index 49da1e5a..00b1a87d 100644 --- a/cryptography/README.md +++ b/cryptography/README.md @@ -6,14 +6,27 @@ Popular cryptographic algorithms for [Dart](https://dart.dev) / [Flutter](https://flutter.dev) developers. -Maintained by [gohilla.com](https://gohilla.com). Licensed under the [Apache License 2.0](LICENSE). - -This package is designed to be: - -* __Easy to use__. The API is easy to understand and encourages good defaults. -* __Multi-platform__. It's easy to customize implementation of X in platform Y. -* __Fast.__ We use platform APIs when available. For example, SHA-512 is over 100 times faster than - _package:crypto_ in browsers. +Maintained by [terrier989](https://github.com/terrier989). +Licensed under the [Apache License 2.0](LICENSE). + +## Key features +* __Defaults to platform-provided implementations.__ + * Android: [javax.crypto](https://developer.android.com/reference/javax/crypto/package-summary) + * iOS / Mac OS X: [Apple CryptoKit](https://developer.apple.com/documentation/cryptokit/) + * Web: [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) +* __Works in all platforms.__ + * We have written Dart implementations for the vast majority of algorithms. When a platform does + not provide a required algorithm, the package automatically falls back to pure Dart + implementation. + * In browsers, both Javascript and WASM compilers are supported. Dart implementations of 64-bit + algorithms like Blake2B have been written to work with Javascript's 53-bit integers. +* __Flexible.__ + * You can override factory methods in [Cryptography](https://pub.dev/documentation/cryptography/latest/cryptography/Cryptography-class.html) + class if you want to use something else. Note that algorithms that you don't use do not affect + size of the executable because of tree pruning. + * You can override random number generator with a deterministic one for tests. +* __Fast.__ + * For example, SHA-512 is over 100 times faster than _package:crypto_ in browsers. Any feedback, issue reports, or pull requests are appreciated! @@ -33,8 +46,10 @@ Android / iOS / Mac OS X operating system APIs whenever possible. In _pubspec.yaml_: ```yaml dependencies: - cryptography: ^2.7.0 - cryptography_flutter: ^2.3.2 # Remove if you don't use Flutter + cryptography: ^2.8.0 + + # If you are writing a Flutter app/package, also add this: + cryptography_flutter: ^2.3.3 ``` You are ready to go! @@ -239,8 +254,8 @@ We wrote the following three implementations of `Cryptography`: for list algorithms supported by it. * [BrowserCryptography](https://pub.dev/documentation/cryptography/latest/cryptography/BrowserCryptography-class.html) * Uses [Web Cryptography API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) - (_crypto.subtle_) whenever possible. Methods return pure Dart implementations when Web - Cryptography API is not available. + whenever possible. Methods return pure Dart implementations when Web Cryptography API is not + available. * See the [class documentation](https://pub.dev/documentation/cryptography/latest/cryptography/BrowserCryptography-class.html) for list algorithms supported by it. * [FlutterCryptography](https://pub.dev/documentation/cryptography_flutter/latest/cryptography_flutter/FlutterCryptography-class.html) diff --git a/cryptography/dart_test.yaml b/cryptography/dart_test.yaml index cbaa1310..aee708a0 100644 --- a/cryptography/dart_test.yaml +++ b/cryptography/dart_test.yaml @@ -2,4 +2,5 @@ platforms: - vm - chrome compilers: + - dart2wasm - dart2js \ No newline at end of file diff --git a/cryptography/lib/browser.dart b/cryptography/lib/browser.dart index f578cce7..f27add2a 100644 --- a/cryptography/lib/browser.dart +++ b/cryptography/lib/browser.dart @@ -20,4 +20,4 @@ library; export 'src/browser/browser_cryptography_when_not_browser.dart' - if (dart.library.html) 'src/browser/browser_cryptography.dart'; + if (dart.library.js_interop) 'src/browser/browser_cryptography.dart'; diff --git a/cryptography/lib/cryptography.dart b/cryptography/lib/cryptography.dart index 1a84609a..42c6328f 100644 --- a/cryptography/lib/cryptography.dart +++ b/cryptography/lib/cryptography.dart @@ -29,7 +29,7 @@ library; import 'package:cryptography/cryptography.dart'; export 'src/browser/browser_cryptography_when_not_browser.dart' - if (dart.library.html) 'src/browser/browser_cryptography.dart'; + if (dart.library.js_interop) 'src/browser/browser_cryptography.dart'; export 'src/cryptography/algorithms.dart'; export 'src/cryptography/cipher.dart'; export 'src/cryptography/cipher_state.dart'; diff --git a/cryptography/lib/src/browser/_javascript_bindings.dart b/cryptography/lib/src/browser/_javascript_bindings.dart index b8d40d42..d391a6d9 100644 --- a/cryptography/lib/src/browser/_javascript_bindings.dart +++ b/cryptography/lib/src/browser/_javascript_bindings.dart @@ -16,21 +16,18 @@ library; import 'dart:convert' show base64Url; -import 'dart:html' show CryptoKey; -import 'dart:html' as html; +import 'dart:js_interop'; import 'dart:typed_data'; -import 'package:js/js.dart'; -import 'package:js/js_util.dart' show promiseToFuture; - -export 'dart:html' show CryptoKey; - /// Note that browsers support Web Cryptography only in secure contexts. final bool isWebCryptoAvailable = - _subtle != null && (html.window.isSecureContext ?? false); + _subtle.isDefinedAndNotNull && _isSecureContext.toDart; @JS('crypto.subtle') -external Object? get _subtle; +external JSAny get _subtle; + +@JS('window.isSecureContext') +external JSBoolean get _isSecureContext; Uint8List base64UrlDecode(String s) { switch (s.length % 4) { @@ -60,6 +57,13 @@ Uint8List? base64UrlDecodeUnmodifiableMaybe(String? s) { return bytes; } +extension type CryptoKey._(JSObject _) implements JSObject { + external JSAny get type; + external bool get extractable; + external JSObject get algorithm; + external JSObject get usages; +} + String base64UrlEncode(List data) { var s = base64Url.encode(data); // Remove trailing '=' characters @@ -78,472 +82,402 @@ String? base64UrlEncodeMaybe(List? data) { } Future decrypt( - dynamic algorithm, + JSAny algorithm, CryptoKey key, - ByteBuffer data, -) { - return promiseToFuture( - _decrypt(algorithm, key, data), - ); + JSUint8Array data, +) async { + final js = await _decrypt(algorithm, key, data).toDart; + return js.toDart; } Future deriveBits( - dynamic algorithm, + JSAny algorithm, CryptoKey cryptoKey, - int bits, -) { - return promiseToFuture( - _deriveBits(algorithm, cryptoKey, bits), - ); + JSNumber bits, +) async { + final js = await _deriveBits(algorithm, cryptoKey, bits).toDart; + return js.toDart; } Future deriveKey( - dynamic algorithm, + JSObject algorithm, CryptoKey baseKey, - dynamic derivedKeyAlgorithm, - dynamic extractable, - List keyUsages, -) { - return promiseToFuture( - _deriveKey( - algorithm, - baseKey, - derivedKeyAlgorithm, - extractable, - keyUsages, - ), - ); + JSObject derivedKeyAlgorithm, + JSBoolean extractable, + JSArray keyUsages, +) async { + final js = await _deriveKey( + algorithm, + baseKey, + derivedKeyAlgorithm, + extractable, + keyUsages, + ).toDart; + return js; } Future digest( String name, - ByteBuffer data, -) { - return promiseToFuture( - _digest(name, data), - ); + JSUint8Array data, +) async { + final js = await _digest(name.toJS, data).toDart; + return js.toDart; } Future encrypt( - dynamic algorithm, + JSAny algorithm, CryptoKey key, - ByteBuffer data, -) { - return promiseToFuture( - _encrypt(algorithm, key, data), - ); + JSUint8Array data, +) async { + final js = await _encrypt(algorithm, key, data).toDart; + return js.toDart; } -Future exportKeyWhenJwk(CryptoKey key) { - return promiseToFuture( - _exportKey('jwk', key), - ); +Future exportKeyWhenJwk(CryptoKey key) async { + final js = await _exportKey('jwk'.toJS, key).toDart; + return js as Jwk; } -Future exportKeyWhenRaw(CryptoKey key) { - return promiseToFuture( - _exportKey('raw', key), - ); +Future exportKeyWhenRaw(CryptoKey key) async { + final js = await _exportKey('raw'.toJS, key).toDart; + return (js as JSArrayBuffer).toDart; } Future generateKeyWhenKey( - Object algorithm, - bool extractable, - List keyUsages, -) { - return promiseToFuture( - _generateKey(algorithm, extractable, keyUsages), - ); + JSAny algorithm, + JSBoolean extractable, + JSArray keyUsages, +) async { + final js = await _generateKey(algorithm, extractable, keyUsages).toDart; + return js as CryptoKey; } Future generateKeyWhenKeyPair( - Object algorithm, - bool extractable, - List keyUsages, -) { - return promiseToFuture( - _generateKey(algorithm, extractable, keyUsages), - ); + JSObject algorithm, + JSBoolean extractable, + JSArray keyUsages, +) async { + final js = await _generateKey(algorithm, extractable, keyUsages).toDart; + return js as CryptoKeyPair; } Future importKeyWhenJwk( Jwk keyData, - dynamic algorithm, - bool extractable, - List keyUsages, -) { - return promiseToFuture( - _importKey( - 'jwk', - keyData, - algorithm, - extractable, - keyUsages, - ), - ); + JSAny algorithm, + JSBoolean extractable, + JSArray keyUsages, +) async { + final js = await _importKey( + 'jwk'.toJS, + keyData.jsObject, + algorithm, + extractable, + keyUsages, + ).toDart; + return js; } Future importKeyWhenRaw( - ByteBuffer keyData, - dynamic algorithm, - bool extractable, - List keyUsages, -) { - return promiseToFuture( - _importKey( - 'raw', - keyData, - algorithm, - extractable, - keyUsages, - ), - ); -} - -ByteBuffer jsArrayBufferFrom(List data) { - // Avoid copying if possible - // - if (data is Uint8List && - data.offsetInBytes == 0 && - data.lengthInBytes == data.buffer.lengthInBytes) { - // We need to check the type because UnmodifiableByteBufferView would cause - // an error. - final buffer = data.buffer; - if (identical(buffer.runtimeType, ByteBuffer)) { - return buffer; - } + JSUint8Array keyData, + JSAny algorithm, + JSBoolean extractable, + JSArray keyUsages, +) async { + final js = await _importKey( + 'raw'.toJS, + keyData, + algorithm, + extractable, + keyUsages, + ).toDart; + return js; +} + +JSUint8Array jsUint8ListFrom(List data) { + if (data is Uint8List) { + return data.toJS; } - - // Copy - return Uint8List.fromList(data).buffer; + return Uint8List.fromList(data).toJS; } Future sign( - dynamic algorithm, + JSAny algorithm, CryptoKey key, - ByteBuffer data, -) { - return promiseToFuture( - _sign(algorithm, key, data), - ); + JSUint8Array data, +) async { + final js = await _sign(algorithm, key, data).toDart; + return js.toDart; } Future verify( - dynamic algorithm, + JSAny algorithm, CryptoKey key, - ByteBuffer signature, - ByteBuffer data, -) { - return promiseToFuture( - _verify(algorithm, key, signature, data), - ); + JSUint8Array signature, + JSUint8Array data, +) async { + final js = await _verify(algorithm, key, signature, data).toDart; + return js.toDart; } @JS('crypto.subtle.decrypt') -external Promise _decrypt( - dynamic algorithm, +external JSPromise _decrypt( + JSAny algorithm, CryptoKey key, - ByteBuffer data, + JSUint8Array data, ); @JS('crypto.subtle.deriveBits') -external Promise _deriveBits( - dynamic algorithm, +external JSPromise _deriveBits( + JSAny algorithm, CryptoKey cryptoKey, - int bits, + JSNumber bits, ); @JS('crypto.subtle.deriveKey') -external Promise _deriveKey( - dynamic algorithm, +external JSPromise _deriveKey( + JSAny algorithm, CryptoKey baseKey, - dynamic derivedKeyAlgorithm, - dynamic extractable, - List keyUsages, + JSAny derivedKeyAlgorithm, + JSBoolean extractable, + JSArray keyUsages, ); @JS('crypto.subtle.digest') -external Promise _digest( - String name, - ByteBuffer data, +external JSPromise _digest( + JSString name, + JSUint8Array data, ); @JS('crypto.subtle.encrypt') -external Promise _encrypt( - dynamic algorithm, +external JSPromise _encrypt( + JSAny algorithm, CryptoKey key, - ByteBuffer data, + JSUint8Array data, ); @JS('crypto.subtle.exportKey') -external Promise _exportKey( - String format, +external JSPromise _exportKey( + JSString format, CryptoKey key, ); @JS('crypto.subtle.generateKey') -external Promise _generateKey( - Object algorithm, - bool extractable, - List keyUsages, +external JSPromise _generateKey( + JSAny algorithm, + JSBoolean extractable, + JSArray keyUsages, ); @JS('crypto.subtle.importKey') -external Promise _importKey( - String format, - dynamic keyData, - dynamic algorithm, - bool extractable, - List keyUsages, +external JSPromise _importKey( + JSString format, + JSAny keyData, + JSAny algorithm, + JSBoolean extractable, + JSArray keyUsages, ); @JS('crypto.subtle.sign') -external Promise _sign( - dynamic algorithm, +external JSPromise _sign( + JSAny algorithm, CryptoKey key, - ByteBuffer data, + JSUint8Array data, ); @JS('crypto.subtle.verify') -external Promise _verify( - dynamic algorithm, +external JSPromise _verify( + JSAny algorithm, CryptoKey key, - ByteBuffer signature, - ByteBuffer data, + JSUint8Array signature, + JSUint8Array data, ); -@JS() -@anonymous -class AesCbcParams { +extension type AesCbcParams._(JSObject jsObject) { external factory AesCbcParams({ - required String name, - required ByteBuffer iv, + required JSString name, + required JSUint8Array iv, }); } -@JS() -@anonymous -class AesCtrParams { +extension type AesCtrParams._(JSObject jsObject) { external factory AesCtrParams({ - required String name, - required ByteBuffer counter, - required int length, + required JSString name, + required JSUint8Array counter, + required JSNumber length, }); } -@JS() -@anonymous -class AesGcmParams { +extension type AesGcmParams._(JSObject jsObject) { external factory AesGcmParams({ - required String name, - required ByteBuffer iv, - ByteBuffer? additionalData, - required int tagLength, + required JSString name, + required JSUint8Array iv, + JSUint8Array? additionalData, + required JSNumber tagLength, }); } -@JS() -@anonymous -class AesKeyGenParams { +extension type AesKeyGenParams._(JSObject jsObject) { external factory AesKeyGenParams({ - required String name, - required int length, + required JSString name, + required JSNumber length, }); } -@JS('CryptoKeyPair') -class CryptoKeyPair { - external factory CryptoKeyPair._(); - +extension type CryptoKeyPair._(JSObject jsObject) { external CryptoKey get privateKey; external CryptoKey get publicKey; } -@JS() -@anonymous -class EcdhKeyDeriveParams { +extension type EcdhKeyDeriveParams._(JSObject jsObject) { external factory EcdhKeyDeriveParams({ - required String name, + required JSString name, required CryptoKey public, }); } -@JS() -@anonymous -class EcdhParams { +extension type EcdhParams._(JSObject jsObject) { external factory EcdhParams({ - required String name, - required String namedCurve, + required JSString name, + required JSString namedCurve, }); } -@JS() -@anonymous -class EcdsaParams { +extension type EcdsaParams._(JSObject jsObject) { external factory EcdsaParams({ - required String name, - required String hash, + required JSString name, + required JSString hash, }); } -@JS() -@anonymous -class EcKeyGenParams { +extension type EcKeyGenParams._(JSObject jsObject) { external factory EcKeyGenParams({ - required String name, - required String namedCurve, + required JSString name, + required JSString namedCurve, }); } -@JS() -@anonymous -class EcKeyImportParams { +extension type EcKeyImportParams._(JSObject jsObject) { external factory EcKeyImportParams({ - required String name, - required String namedCurve, + required JSString name, + required JSString namedCurve, }); } -@JS() -@anonymous -class HkdfParams { +extension type HkdfParams._(JSObject jsObject) { external factory HkdfParams({ - required String name, - required String hash, - required ByteBuffer salt, - required ByteBuffer info, + required JSString name, + required JSString hash, + required JSUint8Array salt, + required JSUint8Array info, }); } -@JS() -@anonymous -class HmacImportParams { +extension type HmacImportParams._(JSObject jsObject) { external factory HmacImportParams({ - required String name, - required String hash, - int? length, + required JSString name, + required JSString hash, + JSNumber? length, }); } -@JS() -@anonymous -class HmacKeyGenParams { +extension type HmacKeyGenParams._(JSObject jsObject) { external factory HmacKeyGenParams({ - required String name, - required String hash, - required int length, + required JSString name, + required JSString hash, + required JSNumber length, }); } -@JS() -@anonymous -class Jwk { +extension type Jwk._(JSObject jsObject) { external factory Jwk({ - String? crv, - String? n, - String? e, - String? d, - String? p, - String? q, - String? dp, - String? dq, - String? qi, - bool? ext, + JSString? crv, + JSString? n, + JSString? e, + JSString? d, + JSString? p, + JSString? q, + JSString? dp, + JSString? dq, + JSString? qi, + JSBoolean? ext, // ignore: non_constant_identifier_names - List? key_ops, - required String kty, - String? x, - String? y, + JSArray? key_ops, + required JSString kty, + JSString? x, + JSString? y, }); - external String? get crv; + external JSString? get crv; - external String? get d; + external JSString? get d; - external String? get dp; + external JSString? get dp; - external String? get dq; + external JSString? get dq; - external String? get e; + external JSString? get e; - external bool get ext; + external JSBoolean get ext; // ignore: non_constant_identifier_names - external List get key_ops; + external JSArray get key_ops; - external String get kty; + external JSString get kty; - external String? get n; + external JSString? get n; - external String? get p; + external JSString? get p; - external String? get q; + external JSString? get q; - external String? get qi; + external JSString? get qi; - external String? get x; + external JSString? get x; - external String? get y; + external JSString? get y; } -@JS() -@anonymous -class Pkdf2Params { +extension type Pkdf2Params._(JSObject jsObject) { external factory Pkdf2Params({ - required String name, - required String hash, - required ByteBuffer salt, - required int iterations, + required JSString name, + required JSString hash, + required JSUint8Array salt, + required JSNumber iterations, }); } -@JS('Promise') -class Promise { - external factory Promise._(); -} - -@JS() -@anonymous -class RsaHashedImportParams { +extension type RsaHashedImportParams._(JSObject jsObject) { external factory RsaHashedImportParams({ - required String name, - required String hash, + required JSString name, + required JSString hash, }); } -@JS() -@anonymous -class RsaHashedKeyGenParams { +extension type RsaHashedKeyGenParams._(JSObject jsObject) { external factory RsaHashedKeyGenParams({ - required String name, - required int modulusLength, - required dynamic publicExponent, - required String hash, + required JSString name, + required JSNumber modulusLength, + required JSUint8Array publicExponent, + required JSString hash, }); } -@JS() -@anonymous -class RsaPssParams { +extension type RsaPssParams._(JSObject jsObject) { external factory RsaPssParams({ - required String name, - int? saltLength, + required JSString name, + JSNumber? saltLength, }); } -@JS() -@anonymous -class SignParams { +extension type SignParams._(JSObject jsObject) { external factory SignParams({ - required String name, + required JSString name, }); } -@JS() -@anonymous -class VerifyParams { +extension type VerifyParams._(JSObject jsObject) { external factory VerifyParams({ - required String name, + required JSString name, }); } diff --git a/cryptography/lib/src/browser/aes_cbc.dart b/cryptography/lib/src/browser/aes_cbc.dart index c2ec8313..c3ed4cc9 100644 --- a/cryptography/lib/src/browser/aes_cbc.dart +++ b/cryptography/lib/src/browser/aes_cbc.dart @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; import 'browser_secret_key.dart'; @@ -69,11 +70,11 @@ class BrowserAesCbc extends AesCbc { ); final byteBuffer = await web_crypto.decrypt( web_crypto.AesCbcParams( - name: _webCryptoName, - iv: jsArrayBufferFrom(secretBox.nonce), - ), + name: _webCryptoName.toJS, + iv: jsUint8ListFrom(secretBox.nonce), + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(secretBox.cipherText), + jsUint8ListFrom(secretBox.cipherText), ); return Uint8List.view(byteBuffer); } @@ -99,11 +100,11 @@ class BrowserAesCbc extends AesCbc { ); final byteBuffer = await web_crypto.encrypt( web_crypto.AesCbcParams( - name: _webCryptoName, - iv: jsArrayBufferFrom(nonce), - ), + name: _webCryptoName.toJS, + iv: jsUint8ListFrom(nonce), + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(clearText), + jsUint8ListFrom(clearText), ); final cipherText = Uint8List.view(byteBuffer); diff --git a/cryptography/lib/src/browser/aes_ctr.dart b/cryptography/lib/src/browser/aes_ctr.dart index bfe49e0f..8538d223 100644 --- a/cryptography/lib/src/browser/aes_ctr.dart +++ b/cryptography/lib/src/browser/aes_ctr.dart @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; import 'browser_secret_key.dart'; @@ -80,12 +81,12 @@ class BrowserAesCtr extends AesCtr { ); final byteBuffer = await web_crypto.decrypt( web_crypto.AesCtrParams( - name: _webCryptoName, - counter: counterBytes.buffer, - length: counterBits, - ), + name: _webCryptoName.toJS, + counter: jsUint8ListFrom(counterBytes), + length: counterBits.toJS, + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(cipherText), + jsUint8ListFrom(cipherText), ); return Uint8List.view(byteBuffer, keyStreamIndex); } @@ -120,12 +121,12 @@ class BrowserAesCtr extends AesCtr { ); final byteBuffer = await web_crypto.encrypt( web_crypto.AesCtrParams( - name: _webCryptoName, - counter: counterBytes.buffer, - length: counterBits, - ), + name: _webCryptoName.toJS, + counter: jsUint8ListFrom(counterBytes), + length: counterBits.toJS, + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(clearText), + jsUint8ListFrom(clearText), ); final cipherText = Uint8List.view(byteBuffer, keyStreamIndex); diff --git a/cryptography/lib/src/browser/aes_gcm.dart b/cryptography/lib/src/browser/aes_gcm.dart index 3f9851ed..869592ba 100644 --- a/cryptography/lib/src/browser/aes_gcm.dart +++ b/cryptography/lib/src/browser/aes_gcm.dart @@ -12,14 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:html' as html; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; + import 'dart:math'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; import 'package:cryptography/src/browser/browser_secret_key.dart'; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; /// AES-GCM implementation that uses _Web Cryptography API_ in browsers. @@ -89,18 +91,22 @@ class BrowserAesGcm extends AesGcm implements StreamingCipher { try { final byteBuffer = await web_crypto.decrypt( web_crypto.AesGcmParams( - name: _webCryptoName, - iv: jsArrayBufferFrom(secretBox.nonce), - additionalData: jsArrayBufferFrom(aad), - tagLength: macBytes.length * 8, - ), + name: _webCryptoName.toJS, + iv: jsUint8ListFrom(secretBox.nonce), + additionalData: jsUint8ListFrom(aad), + tagLength: (macBytes.length * 8).toJS, + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(cipherTextAndMac), + jsUint8ListFrom(cipherTextAndMac), ); return Uint8List.view(byteBuffer); - } on html.DomException catch (e) { - if (e.name == 'OperationError') { - throw SecretBoxAuthenticationError(); + } catch (e) { + final js = JSObject.fromInteropObject(e); + if (js.hasProperty('name'.toJS).toDart) { + final name = (js.getProperty('name'.toJS) as JSString).toDart; + if (name == 'OperationError') { + throw SecretBoxAuthenticationError(); + } } rethrow; } @@ -134,13 +140,13 @@ class BrowserAesGcm extends AesGcm implements StreamingCipher { ); final byteBuffer = await web_crypto.encrypt( web_crypto.AesGcmParams( - name: 'AES-GCM', - iv: jsArrayBufferFrom(nonce), - additionalData: jsArrayBufferFrom(aad), - tagLength: macAlgorithm.macLength * 8, - ), + name: 'AES-GCM'.toJS, + iv: jsUint8ListFrom(nonce), + additionalData: jsUint8ListFrom(aad), + tagLength: (macAlgorithm.macLength * 8).toJS, + ).jsObject, jsCryptoKey, - jsArrayBufferFrom(clearText), + jsUint8ListFrom(clearText), ); final cipherText = Uint8List.view( diff --git a/cryptography/lib/src/browser/browser_cryptography.dart b/cryptography/lib/src/browser/browser_cryptography.dart index 0ff67428..91ac7334 100644 --- a/cryptography/lib/src/browser/browser_cryptography.dart +++ b/cryptography/lib/src/browser/browser_cryptography.dart @@ -44,12 +44,15 @@ class BrowserCryptography extends DartCryptography { // Documented in browser_cryptography_when_not_browser.dart static bool get isSupported => isWebCryptoAvailable && !isDisabledForTesting; + // Documented in browser_cryptography_when_not_browser.dart + static bool get isRunningInWasm => (0 as num) is! double; + final Random? _random; // Documented in browser_cryptography_when_not_browser.dart BrowserCryptography({ super.random, - }) : _random = random; + }) : _random = random; @override AesCbc aesCbc({ diff --git a/cryptography/lib/src/browser/browser_cryptography_when_not_browser.dart b/cryptography/lib/src/browser/browser_cryptography_when_not_browser.dart index 56fb6d29..e0092e48 100644 --- a/cryptography/lib/src/browser/browser_cryptography_when_not_browser.dart +++ b/cryptography/lib/src/browser/browser_cryptography_when_not_browser.dart @@ -77,6 +77,9 @@ class BrowserCryptography extends DartCryptography { /// always available. static bool get isSupported => false; + /// Whether WASM is used. + static bool get isRunningInWasm => false; + /// Constructs an instance of [BrowserCryptography]. /// /// If [random] is not given, algorithms will use some cryptographically diff --git a/cryptography/lib/src/browser/browser_ec_key_pair.dart b/cryptography/lib/src/browser/browser_ec_key_pair.dart index 3c860e69..3a2732eb 100644 --- a/cryptography/lib/src/browser/browser_ec_key_pair.dart +++ b/cryptography/lib/src/browser/browser_ec_key_pair.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:typed_data'; import '../../cryptography.dart'; @@ -73,9 +74,9 @@ class BrowserEcKeyPair extends KeyPair implements EcKeyPair { ); return EcKeyPairData( type: keyPairType, - d: web_crypto.base64UrlDecodeUnmodifiable(jwk.d!), - x: web_crypto.base64UrlDecodeUnmodifiable(jwk.x!), - y: web_crypto.base64UrlDecodeUnmodifiable(jwk.y!), + d: web_crypto.base64UrlDecodeUnmodifiable(jwk.d!.toDart), + x: web_crypto.base64UrlDecodeUnmodifiable(jwk.x!.toDart), + y: web_crypto.base64UrlDecodeUnmodifiable(jwk.y!.toDart), ); } catch (error, stackTrace) { throw StateError( @@ -147,83 +148,91 @@ class BrowserEcKeyPair extends KeyPair implements EcKeyPair { final futures = []; if (allowSign) { // Private key - futures.add(web_crypto.importKeyWhenJwk( + futures.add(web_crypto + .importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: isExtractable, - key_ops: const ['sign'], - d: d_, - x: x_, - y: y_, + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: isExtractable.toJS, + key_ops: ['sign'.toJS].toJS, + d: d_.toJS, + x: x_.toJS, + y: y_.toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDSA', - namedCurve: webCryptoCurve, - ), - isExtractable, - const ['sign'], - ).then((value) { + name: 'ECDSA'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + isExtractable.toJS, + ['sign'.toJS].toJS, + ) + .then((value) { jsPrivateKeyForEcdsa = value; })); // Public key - futures.add(web_crypto.importKeyWhenJwk( + futures.add(web_crypto + .importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: true, - key_ops: const ['verify'], - x: x_, - y: y_, + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: true.toJS, + key_ops: ['verify'.toJS].toJS, + x: x_.toJS, + y: y_.toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDSA', - namedCurve: webCryptoCurve, - ), - true, - const [], - ).then((value) { + name: 'ECDSA'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + true.toJS, + (const []).toJS, + ) + .then((value) { jsPublicKeyForEcdsa = value; })); } if (allowDeriveBits) { // Private key - futures.add(web_crypto.importKeyWhenJwk( + futures.add(web_crypto + .importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: isExtractable, - key_ops: const ['deriveBits'], - d: d_, - x: x_, - y: y_, + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: isExtractable.toJS, + key_ops: ['deriveBits'.toJS].toJS, + d: d_.toJS, + x: x_.toJS, + y: y_.toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDH', - namedCurve: webCryptoCurve, - ), - isExtractable, - const ['deriveBits'], - ).then((value) { + name: 'ECDH'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + isExtractable.toJS, + ['deriveBits'.toJS].toJS, + ) + .then((value) { jsPrivateKeyForEcdh = value; })); // Public key - futures.add(web_crypto.importKeyWhenJwk( + futures.add(web_crypto + .importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: true, - key_ops: const ['deriveBits'], - x: x_, - y: y_, + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: true.toJS, + key_ops: ['deriveBits'.toJS].toJS, + x: x_.toJS, + y: y_.toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDH', - namedCurve: webCryptoCurve, - ), - true, - const [], - ).then((value) { + name: 'ECDH'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + true.toJS, + const [].toJS, + ) + .then((value) { jsPublicKeyForEcdh = value; })); } @@ -259,20 +268,20 @@ class BrowserEcKeyPair extends KeyPair implements EcKeyPair { try { final jsKey = await web_crypto.generateKeyWhenKeyPair( web_crypto.EcKeyGenParams( - name: 'ECDSA', - namedCurve: keyPairType.webCryptoCurve!, - ), - true, - ['sign'], + name: 'ECDSA'.toJS, + namedCurve: keyPairType.webCryptoCurve!.toJS, + ).jsObject, + true.toJS, + ['sign'.toJS].toJS, ); final jwk = await web_crypto.exportKeyWhenJwk( jsKey.privateKey, ); return fromParameters( keyPairType: keyPairType, - d: web_crypto.base64UrlDecodeUnmodifiable(jwk.d!), - x: web_crypto.base64UrlDecodeUnmodifiable(jwk.x!), - y: web_crypto.base64UrlDecodeUnmodifiable(jwk.y!), + d: web_crypto.base64UrlDecodeUnmodifiable(jwk.d!.toDart), + x: web_crypto.base64UrlDecodeUnmodifiable(jwk.x!.toDart), + y: web_crypto.base64UrlDecodeUnmodifiable(jwk.y!.toDart), isExtractable: isExtractable, allowSign: allowSign, allowDeriveBits: allowDeriveBits, diff --git a/cryptography/lib/src/browser/browser_secret_key.dart b/cryptography/lib/src/browser/browser_secret_key.dart index 621f17d3..caa80e99 100644 --- a/cryptography/lib/src/browser/browser_secret_key.dart +++ b/cryptography/lib/src/browser/browser_secret_key.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -127,16 +128,16 @@ class BrowserSecretKey extends SecretKey { required Random? random, }) async { final usages = [ - if (allowEncrypt) 'encrypt', - if (allowDecrypt) 'decrypt', - ]; + if (allowEncrypt) 'encrypt'.toJS, + if (allowDecrypt) 'decrypt'.toJS, + ].toJS; if (random != null) { final bytes = Uint8List(secretKeyLength); fillBytesWithSecureRandom(bytes, random: random); final jsCryptoKey = await web_crypto.importKeyWhenRaw( - web_crypto.jsArrayBufferFrom(bytes), - webCryptoAlgorithm, - isExtractable, + web_crypto.jsUint8ListFrom(bytes), + webCryptoAlgorithm.toJS, + isExtractable.toJS, usages, ); return BrowserSecretKey( @@ -149,10 +150,10 @@ class BrowserSecretKey extends SecretKey { } final jsCryptoKey = await web_crypto.generateKeyWhenKey( web_crypto.AesKeyGenParams( - name: webCryptoAlgorithm, - length: secretKeyLength * 8, - ), - isExtractable, + name: webCryptoAlgorithm.toJS, + length: (secretKeyLength * 8).toJS, + ).jsObject, + isExtractable.toJS, usages, ); return BrowserSecretKey( @@ -186,13 +187,13 @@ class BrowserSecretKey extends SecretKey { throw _secretKeyLengthError(actualSecretKeyLength, secretKeyLength); } return web_crypto.importKeyWhenRaw( - jsArrayBufferFrom(secretKeyBytes), - webCryptoAlgorithm, - isExtractable, + jsUint8ListFrom(secretKeyBytes), + webCryptoAlgorithm.toJS, + isExtractable.toJS, [ - if (allowEncrypt) 'encrypt', - if (allowDecrypt) 'decrypt', - ], + if (allowEncrypt) 'encrypt'.toJS, + if (allowDecrypt) 'decrypt'.toJS, + ].toJS, ); } diff --git a/cryptography/lib/src/browser/ecdh.dart b/cryptography/lib/src/browser/ecdh.dart index eacba5e9..1e20c7c0 100644 --- a/cryptography/lib/src/browser/ecdh.dart +++ b/cryptography/lib/src/browser/ecdh.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -109,11 +110,11 @@ class BrowserEcdh extends Ecdh { try { final byteBuffer = await web_crypto.deriveBits( web_crypto.EcdhKeyDeriveParams( - name: 'ECDH', + name: 'ECDH'.toJS, public: jsPublicKey, - ), + ).jsObject, jsPrivateKey.jsPrivateKeyForEcdh!, - 8 * length, + (8 * length).toJS, ); return SecretKey(Uint8List.view(byteBuffer)); } catch (error, stackTrace) { @@ -137,19 +138,19 @@ class BrowserEcdh extends Ecdh { try { return await web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: true, - key_ops: const ['deriveBits'], - x: web_crypto.base64UrlEncode(publicKey.x), - y: web_crypto.base64UrlEncode(publicKey.y), + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: true.toJS, + key_ops: ['deriveBits'.toJS].toJS, + x: web_crypto.base64UrlEncode(publicKey.x).toJS, + y: web_crypto.base64UrlEncode(publicKey.y).toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDH', - namedCurve: webCryptoCurve, - ), - true, - const [], + name: 'ECDH'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + true.toJS, + const [].toJS, ); } catch (error, stackTrace) { throw StateError( diff --git a/cryptography/lib/src/browser/ecdsa.dart b/cryptography/lib/src/browser/ecdsa.dart index ccdb7b4e..45e06544 100644 --- a/cryptography/lib/src/browser/ecdsa.dart +++ b/cryptography/lib/src/browser/ecdsa.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -95,13 +96,14 @@ class BrowserEcdsa extends Ecdsa { final jsCryptoKey = browserEcKeyPair.jsPrivateKeyForEcdsa!; final byteBuffer = await web_crypto.sign( web_crypto.EcdsaParams( - name: 'ECDSA', + name: 'ECDSA'.toJS, hash: BrowserHashAlgorithmMixin.hashAlgorithmNameFor( hashAlgorithm, - )!, - ), + )! + .toJS, + ).jsObject, jsCryptoKey, - web_crypto.jsArrayBufferFrom(message), + web_crypto.jsUint8ListFrom(message), ); return Signature( Uint8List.view(byteBuffer), @@ -132,12 +134,12 @@ class BrowserEcdsa extends Ecdsa { ); return await web_crypto.verify( web_crypto.EcdsaParams( - name: 'ECDSA', - hash: hashAlgorithmName, - ), + name: 'ECDSA'.toJS, + hash: hashAlgorithmName.toJS, + ).jsObject, jsCryptoKey, - web_crypto.jsArrayBufferFrom(signature.bytes), - web_crypto.jsArrayBufferFrom(message), + web_crypto.jsUint8ListFrom(signature.bytes), + web_crypto.jsUint8ListFrom(message), ); } @@ -155,19 +157,19 @@ class BrowserEcdsa extends Ecdsa { } return web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'EC', - crv: webCryptoCurve, - ext: true, - key_ops: const ['verify'], - x: web_crypto.base64UrlEncode(publicKey.x), - y: web_crypto.base64UrlEncode(publicKey.y), + kty: 'EC'.toJS, + crv: webCryptoCurve.toJS, + ext: true.toJS, + key_ops: ['verify'.toJS].toJS, + x: web_crypto.base64UrlEncode(publicKey.x).toJS, + y: web_crypto.base64UrlEncode(publicKey.y).toJS, ), web_crypto.EcKeyImportParams( - name: 'ECDSA', - namedCurve: webCryptoCurve, - ), - false, - const ['verify'], + name: 'ECDSA'.toJS, + namedCurve: webCryptoCurve.toJS, + ).jsObject, + false.toJS, + ['verify'.toJS].toJS, ); } } diff --git a/cryptography/lib/src/browser/hash.dart b/cryptography/lib/src/browser/hash.dart index 3c99f095..03e1541c 100644 --- a/cryptography/lib/src/browser/hash.dart +++ b/cryptography/lib/src/browser/hash.dart @@ -18,7 +18,7 @@ import 'package:cryptography/cryptography.dart'; import 'package:meta/meta.dart'; import '_javascript_bindings.dart' as web_crypto; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; mixin BrowserHashAlgorithmMixin implements HashAlgorithm { /// Web Cryptography API algorithm name ("SHA-256", etc.). @@ -28,7 +28,7 @@ mixin BrowserHashAlgorithmMixin implements HashAlgorithm { Future hash(List bytes) async { final byteBuffer = await web_crypto.digest( webCryptoName, - jsArrayBufferFrom(bytes), + jsUint8ListFrom(bytes), ); return Hash(Uint8List.view(byteBuffer)); } diff --git a/cryptography/lib/src/browser/hkdf.dart b/cryptography/lib/src/browser/hkdf.dart index d94920c1..30834e37 100644 --- a/cryptography/lib/src/browser/hkdf.dart +++ b/cryptography/lib/src/browser/hkdf.dart @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; import 'package:cryptography/src/browser/hash.dart'; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; /// HKDF implementation that uses _Web Cryptography API_ in browsers. @@ -39,18 +40,24 @@ class BrowserHkdf extends Hkdf { List nonce = const [], List info = const [], }) async { + final hashAlgorithmName = BrowserHashAlgorithmMixin.hashAlgorithmNameFor( + hmac.hashAlgorithm, + ); + if (hashAlgorithmName == null) { + throw UnsupportedError( + 'The hash algorithm ${hmac.hashAlgorithm} is not supported by Web Crypto API.', + ); + } final jsCryptoKey = await _jsCryptoKey(secretKey); final byteBuffer = await web_crypto.deriveBits( web_crypto.HkdfParams( - name: 'HKDF', - hash: BrowserHashAlgorithmMixin.hashAlgorithmNameFor( - hmac.hashAlgorithm, - )!, - salt: jsArrayBufferFrom(nonce), - info: jsArrayBufferFrom(info), - ), + name: 'HKDF'.toJS, + hash: hashAlgorithmName.toJS, + salt: jsUint8ListFrom(nonce), + info: jsUint8ListFrom(info), + ).jsObject, jsCryptoKey, - 8 * outputLength, + (8 * outputLength).toJS, ); return SecretKeyData(Uint8List.view(byteBuffer)); } @@ -58,10 +65,10 @@ class BrowserHkdf extends Hkdf { Future _jsCryptoKey(SecretKey secretKey) async { final secretKeyBytes = await secretKey.extractBytes(); return await web_crypto.importKeyWhenRaw( - web_crypto.jsArrayBufferFrom(secretKeyBytes), - 'HKDF', - false, - const ['deriveBits'], + web_crypto.jsUint8ListFrom(secretKeyBytes), + 'HKDF'.toJS, + false.toJS, + ['deriveBits'.toJS].toJS, ); } } diff --git a/cryptography/lib/src/browser/hmac.dart b/cryptography/lib/src/browser/hmac.dart index a475457d..ef7cce35 100644 --- a/cryptography/lib/src/browser/hmac.dart +++ b/cryptography/lib/src/browser/hmac.dart @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; import '_javascript_bindings.dart' as web_crypto; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import 'hash.dart'; /// HMAC implementation that uses _Web Cryptography API_ in browsers. @@ -56,9 +57,9 @@ class BrowserHmac extends Hmac { } final jsCryptoKey = await _jsCryptoKey(secretKey); final byteBuffer = await web_crypto.sign( - 'HMAC', + 'HMAC'.toJS, jsCryptoKey, - jsArrayBufferFrom(bytes), + jsUint8ListFrom(bytes), ); return Mac(Uint8List.view(byteBuffer)); } @@ -73,13 +74,13 @@ class BrowserHmac extends Hmac { ); } return await web_crypto.importKeyWhenRaw( - web_crypto.jsArrayBufferFrom(secretKeyBytes), + web_crypto.jsUint8ListFrom(secretKeyBytes), web_crypto.HmacImportParams( - name: 'HMAC', - hash: hashAlgorithmWebCryptoName, - ), - false, - const ['sign'], + name: 'HMAC'.toJS, + hash: hashAlgorithmWebCryptoName.toJS, + ).jsObject, + false.toJS, + ['sign'.toJS].toJS, ); } } diff --git a/cryptography/lib/src/browser/pbkdf2.dart b/cryptography/lib/src/browser/pbkdf2.dart index 12708a2e..7aa618cf 100644 --- a/cryptography/lib/src/browser/pbkdf2.dart +++ b/cryptography/lib/src/browser/pbkdf2.dart @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; -import '_javascript_bindings.dart' show jsArrayBufferFrom; +import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; import 'hmac.dart'; @@ -49,13 +50,13 @@ class BrowserPbkdf2 extends Pbkdf2 { // subtle.deriveBits(...) final byteBuffer = await web_crypto.deriveBits( web_crypto.Pkdf2Params( - name: 'PBKDF2', - hash: macAlgorithm.hashAlgorithmWebCryptoName, - salt: jsArrayBufferFrom(nonce), - iterations: iterations, - ), + name: 'PBKDF2'.toJS, + hash: macAlgorithm.hashAlgorithmWebCryptoName.toJS, + salt: jsUint8ListFrom(nonce), + iterations: iterations.toJS, + ).jsObject, jsCryptoKey, - bits, + bits.toJS, ); return SecretKey(Uint8List.view(byteBuffer)); @@ -64,10 +65,10 @@ class BrowserPbkdf2 extends Pbkdf2 { Future _jsCryptoKey(SecretKey secretKey) async { final secretKeyData = await secretKey.extract(); return web_crypto.importKeyWhenRaw( - jsArrayBufferFrom(secretKeyData.bytes), - 'PBKDF2', - false, - const ['deriveBits'], + jsUint8ListFrom(secretKeyData.bytes), + 'PBKDF2'.toJS, + false.toJS, + ['deriveBits'.toJS].toJS, ); } } diff --git a/cryptography/lib/src/browser/rsa_pss.dart b/cryptography/lib/src/browser/rsa_pss.dart index 54bed940..2f63b5b5 100644 --- a/cryptography/lib/src/browser/rsa_pss.dart +++ b/cryptography/lib/src/browser/rsa_pss.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -23,7 +24,8 @@ import '_javascript_bindings.dart' base64UrlDecodeUnmodifiable, base64UrlDecodeUnmodifiableMaybe, base64UrlEncode, - base64UrlEncodeMaybe; + base64UrlEncodeMaybe, + jsUint8ListFrom; import 'hash.dart'; /// RSA-PSS implementation that uses _Web Cryptography API_ in browsers. @@ -71,13 +73,13 @@ class BrowserRsaPss extends RsaPss { // Generate CryptoKeyPair final jsCryptoKeyPair = await web_crypto.generateKeyWhenKeyPair( web_crypto.RsaHashedKeyGenParams( - name: _webCryptoAlgorithm, - modulusLength: modulusLength, - publicExponent: Uint8List.fromList(publicExponent), - hash: webCryptoHash, - ), - true, - ['sign', 'verify'], + name: _webCryptoAlgorithm.toJS, + modulusLength: modulusLength.toJS, + publicExponent: web_crypto.jsUint8ListFrom(publicExponent), + hash: webCryptoHash.toJS, + ).jsObject, + true.toJS, + ['sign'.toJS, 'verify'.toJS].toJS, ); return _BrowserRsaPssKeyPair( jsCryptoKeyPair, @@ -107,11 +109,11 @@ class BrowserRsaPss extends RsaPss { ); final byteBuffer = await web_crypto.sign( web_crypto.RsaPssParams( - name: _webCryptoAlgorithm, - saltLength: nonceLengthInBytes, - ), + name: _webCryptoAlgorithm.toJS, + saltLength: nonceLengthInBytes.toJS, + ).jsObject, jsCryptoKey, - web_crypto.jsArrayBufferFrom(message), + Uint8List.fromList(message).toJS, ); return Signature( Uint8List.view(byteBuffer), @@ -139,12 +141,12 @@ class BrowserRsaPss extends RsaPss { ); return await web_crypto.verify( web_crypto.RsaPssParams( - name: _webCryptoAlgorithm, - saltLength: nonceLengthInBytes, - ), + name: _webCryptoAlgorithm.toJS, + saltLength: nonceLengthInBytes.toJS, + ).jsObject, jsCryptoKey, - web_crypto.jsArrayBufferFrom(signature.bytes), - web_crypto.jsArrayBufferFrom(message), + jsUint8ListFrom(signature.bytes), + jsUint8ListFrom(message), ); } @@ -168,22 +170,22 @@ class BrowserRsaPss extends RsaPss { // Import JWK key return web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'RSA', - n: base64UrlEncode(keyPairData.n), - e: base64UrlEncode(keyPairData.e), - p: base64UrlEncode(keyPairData.p), - d: base64UrlEncode(keyPairData.d), - q: base64UrlEncode(keyPairData.q), - dp: base64UrlEncodeMaybe(keyPairData.dp), - dq: base64UrlEncodeMaybe(keyPairData.dq), - qi: base64UrlEncodeMaybe(keyPairData.qi), + kty: 'RSA'.toJS, + n: base64UrlEncode(keyPairData.n).toJS, + e: base64UrlEncode(keyPairData.e).toJS, + p: base64UrlEncode(keyPairData.p).toJS, + d: base64UrlEncode(keyPairData.d).toJS, + q: base64UrlEncode(keyPairData.q).toJS, + dp: base64UrlEncodeMaybe(keyPairData.dp)?.toJS, + dq: base64UrlEncodeMaybe(keyPairData.dq)?.toJS, + qi: base64UrlEncodeMaybe(keyPairData.qi)?.toJS, ), web_crypto.RsaHashedImportParams( - name: webCryptoAlgorithm, - hash: webCryptoHash, - ), - false, - const ['sign'], + name: webCryptoAlgorithm.toJS, + hash: webCryptoHash.toJS, + ).jsObject, + false.toJS, + ['sign'.toJS].toJS, ); } @@ -206,16 +208,16 @@ class BrowserRsaPss extends RsaPss { } return web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'RSA', - n: base64UrlEncode(publicKey.n), - e: base64UrlEncode(publicKey.e), + kty: 'RSA'.toJS, + n: base64UrlEncode(publicKey.n).toJS, + e: base64UrlEncode(publicKey.e).toJS, ), web_crypto.RsaHashedImportParams( - name: webCryptoAlgorithm, - hash: webCryptoHash, - ), - false, - const ['verify'], + name: webCryptoAlgorithm.toJS, + hash: webCryptoHash.toJS, + ).jsObject, + false.toJS, + ['verify'.toJS].toJS, ); } } @@ -237,14 +239,14 @@ class _BrowserRsaPssKeyPair extends RsaKeyPair { jsCryptoKeyPair.privateKey, ); return RsaKeyPairData( - n: base64UrlDecodeUnmodifiable(jsJwk.n!), - e: base64UrlDecodeUnmodifiable(jsJwk.e!), - d: base64UrlDecodeUnmodifiable(jsJwk.d!), - p: base64UrlDecodeUnmodifiable(jsJwk.p!), - q: base64UrlDecodeUnmodifiable(jsJwk.q!), - dp: base64UrlDecodeUnmodifiableMaybe(jsJwk.dp), - dq: base64UrlDecodeUnmodifiableMaybe(jsJwk.dq), - qi: base64UrlDecodeUnmodifiableMaybe(jsJwk.qi), + n: base64UrlDecodeUnmodifiable(jsJwk.n!.toDart), + e: base64UrlDecodeUnmodifiable(jsJwk.e!.toDart), + d: base64UrlDecodeUnmodifiable(jsJwk.d!.toDart), + p: base64UrlDecodeUnmodifiable(jsJwk.p!.toDart), + q: base64UrlDecodeUnmodifiable(jsJwk.q!.toDart), + dp: base64UrlDecodeUnmodifiableMaybe(jsJwk.dp?.toDart), + dq: base64UrlDecodeUnmodifiableMaybe(jsJwk.dq?.toDart), + qi: base64UrlDecodeUnmodifiableMaybe(jsJwk.qi?.toDart), ); } @@ -257,8 +259,8 @@ class _BrowserRsaPssKeyPair extends RsaKeyPair { jsCryptoKey: jsCryptoKeyPair.publicKey, webCryptoAlgorithm: webCryptoAlgorithm, webCryptoHash: webCryptoHash, - n: base64UrlDecodeUnmodifiable(jsJwk.n!), - e: base64UrlDecodeUnmodifiable(jsJwk.e!), + n: base64UrlDecodeUnmodifiable(jsJwk.n!.toDart), + e: base64UrlDecodeUnmodifiable(jsJwk.e!.toDart), ); } } diff --git a/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart b/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart index 87141224..d9489eba 100644 --- a/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart +++ b/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -63,13 +64,13 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { // Generate CryptoKeyPair final jsCryptoKeyPair = await web_crypto.generateKeyWhenKeyPair( web_crypto.RsaHashedKeyGenParams( - name: _webCryptoAlgorithm, - modulusLength: modulusLength, - publicExponent: Uint8List.fromList(publicExponent), - hash: webCryptoHash, - ), - true, - ['sign', 'verify'], + name: _webCryptoAlgorithm.toJS, + modulusLength: modulusLength.toJS, + publicExponent: web_crypto.jsUint8ListFrom(publicExponent), + hash: webCryptoHash.toJS, + ).jsObject, + true.toJS, + ['sign'.toJS, 'verify'.toJS].toJS, ); return _BrowserRsaSsaPkcs1v15KeyPair( jsCryptoKeyPair, @@ -95,9 +96,9 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { webCryptoHash: webCryptoHash, ); final byteBuffer = await web_crypto.sign( - _webCryptoAlgorithm, + _webCryptoAlgorithm.toJS, jsCryptoKey, - web_crypto.jsArrayBufferFrom(message), + web_crypto.jsUint8ListFrom(message), ); return Signature( Uint8List.view(byteBuffer), @@ -121,10 +122,10 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { webCryptoHash: webCryptoHash, ); return await web_crypto.verify( - _webCryptoAlgorithm, + _webCryptoAlgorithm.toJS, jsCryptoKey, - web_crypto.jsArrayBufferFrom(signature.bytes), - web_crypto.jsArrayBufferFrom(message), + web_crypto.jsUint8ListFrom(signature.bytes), + web_crypto.jsUint8ListFrom(message), ); } @@ -148,22 +149,22 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { // Import JWK key return web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'RSA', - n: base64UrlEncode(keyPairData.n), - e: base64UrlEncode(keyPairData.e), - p: base64UrlEncode(keyPairData.p), - d: base64UrlEncode(keyPairData.d), - q: base64UrlEncode(keyPairData.q), - dp: base64UrlEncodeMaybe(keyPairData.dp), - dq: base64UrlEncodeMaybe(keyPairData.dq), - qi: base64UrlEncodeMaybe(keyPairData.qi), + kty: 'RSA'.toJS, + n: base64UrlEncode(keyPairData.n).toJS, + e: base64UrlEncode(keyPairData.e).toJS, + p: base64UrlEncode(keyPairData.p).toJS, + d: base64UrlEncode(keyPairData.d).toJS, + q: base64UrlEncode(keyPairData.q).toJS, + dp: base64UrlEncodeMaybe(keyPairData.dp)?.toJS, + dq: base64UrlEncodeMaybe(keyPairData.dq)?.toJS, + qi: base64UrlEncodeMaybe(keyPairData.qi)?.toJS, ), web_crypto.RsaHashedImportParams( - name: webCryptoAlgorithm, - hash: webCryptoHash, - ), - false, - const ['sign'], + name: webCryptoAlgorithm.toJS, + hash: webCryptoHash.toJS, + ).jsObject, + false.toJS, + ['sign'.toJS].toJS, ); } @@ -186,16 +187,16 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { } return web_crypto.importKeyWhenJwk( web_crypto.Jwk( - kty: 'RSA', - n: base64UrlEncode(publicKey.n), - e: base64UrlEncode(publicKey.e), + kty: 'RSA'.toJS, + n: base64UrlEncode(publicKey.n).toJS, + e: base64UrlEncode(publicKey.e).toJS, ), web_crypto.RsaHashedImportParams( - name: webCryptoAlgorithm, - hash: webCryptoHash, - ), - false, - const ['verify'], + name: webCryptoAlgorithm.toJS, + hash: webCryptoHash.toJS, + ).jsObject, + false.toJS, + ['verify'.toJS].toJS, ); } } @@ -231,14 +232,14 @@ class _BrowserRsaSsaPkcs1v15KeyPair extends KeyPair implements RsaKeyPair { jsCryptoKeyPair.privateKey, ); return RsaKeyPairData( - n: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.n!), - e: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.e!), - d: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.d!), - p: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.p!), - q: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.q!), - dp: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.dp), - dq: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.dq), - qi: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.qi), + n: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.n!.toDart), + e: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.e!.toDart), + d: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.d!.toDart), + p: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.p!.toDart), + q: web_crypto.base64UrlDecodeUnmodifiable(jsJwk.q!.toDart), + dp: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.dp?.toDart), + dq: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.dq?.toDart), + qi: web_crypto.base64UrlDecodeUnmodifiableMaybe(jsJwk.qi?.toDart), ); } @@ -251,8 +252,8 @@ class _BrowserRsaSsaPkcs1v15KeyPair extends KeyPair implements RsaKeyPair { jsCryptoKey: jsCryptoKeyPair.publicKey, webCryptoAlgorithm: webCryptoAlgorithm, webCryptoHash: webCryptoHash, - n: base64UrlDecodeUnmodifiable(jsJwk.n!), - e: base64UrlDecodeUnmodifiable(jsJwk.e!), + n: base64UrlDecodeUnmodifiable(jsJwk.n!.toDart), + e: base64UrlDecodeUnmodifiable(jsJwk.e!.toDart), ); } } diff --git a/cryptography/lib/src/dart/argon2.dart b/cryptography/lib/src/dart/argon2.dart index 3497a476..050b5ef1 100644 --- a/cryptography/lib/src/dart/argon2.dart +++ b/cryptography/lib/src/dart/argon2.dart @@ -20,7 +20,7 @@ import 'package:cryptography/cryptography.dart'; import 'package:cryptography/dart.dart'; import 'package:cryptography/src/dart/_helpers.dart'; import 'package:cryptography/src/dart/argon2_impl_browser.dart' - if (dart.library.ffi) 'package:cryptography/src/dart/argon2_impl_vm.dart'; + if (dart.library.ffi) 'package:cryptography/src/dart/argon2_impl_default.dart'; import 'package:meta/meta.dart'; const _bit32 = 0x100000000; diff --git a/cryptography/lib/src/dart/argon2_impl_browser.dart b/cryptography/lib/src/dart/argon2_impl_browser.dart index 890faee6..d695cee4 100644 --- a/cryptography/lib/src/dart/argon2_impl_browser.dart +++ b/cryptography/lib/src/dart/argon2_impl_browser.dart @@ -16,12 +16,12 @@ import 'dart:typed_data'; import 'package:cryptography/dart.dart'; -typedef DartArgon2StateImpl = DartArgon2StateImplBrowser; +typedef DartArgon2StateImpl = DartArgon2StateImplNoFfi; -class DartArgon2StateImplBrowser extends DartArgon2State { +class DartArgon2StateImplNoFfi extends DartArgon2State { ByteBuffer? _buffer; - DartArgon2StateImplBrowser({ + DartArgon2StateImplNoFfi({ super.version, required super.mode, required super.parallelism, diff --git a/cryptography/lib/src/dart/argon2_impl_vm.dart b/cryptography/lib/src/dart/argon2_impl_default.dart similarity index 98% rename from cryptography/lib/src/dart/argon2_impl_vm.dart rename to cryptography/lib/src/dart/argon2_impl_default.dart index 6e044fff..e78248fc 100644 --- a/cryptography/lib/src/dart/argon2_impl_vm.dart +++ b/cryptography/lib/src/dart/argon2_impl_default.dart @@ -24,9 +24,9 @@ import '../../dart.dart'; const _mask32 = 0xFFFFFFFF; -typedef DartArgon2StateImpl = DartArgon2StateImplVm; +typedef DartArgon2StateImpl = DartArgon2StateImplFfi; -class DartArgon2StateImplVm extends DartArgon2State { +class DartArgon2StateImplFfi extends DartArgon2State { static final _allocator = calloc; static final _finalizer = Finalizer((p0) { _allocator.free(p0); @@ -36,7 +36,7 @@ class DartArgon2StateImplVm extends DartArgon2State { ByteBuffer? _buffer; int _bufferAddress = 0; - DartArgon2StateImplVm({ + DartArgon2StateImplFfi({ super.version, required super.mode, required super.parallelism, @@ -293,7 +293,7 @@ class DartArgon2StateImplVm extends DartArgon2State { final lanesLength = message[11] as int; final pointer = Pointer.fromAddress(bufferAddress); final buffer = pointer.asTypedList(1024 * memory).buffer; - final state = DartArgon2StateImplVm( + final state = DartArgon2StateImplFfi( version: version, mode: mode, memory: memory, diff --git a/cryptography/lib/src/dart/blake2b.dart b/cryptography/lib/src/dart/blake2b.dart index 24a22064..befc95a5 100644 --- a/cryptography/lib/src/dart/blake2b.dart +++ b/cryptography/lib/src/dart/blake2b.dart @@ -15,8 +15,8 @@ import 'package:cryptography/cryptography.dart'; import 'package:cryptography/dart.dart'; -import 'blake2b_impl_vm.dart' - if (dart.library.html) 'blake2b_impl_browser.dart'; +import 'blake2b_impl_default.dart' + if (dart.library.js_interop) 'blake2b_impl_js.dart'; /// [Blake2b] implemented in pure Dart. /// diff --git a/cryptography/lib/src/dart/blake2b_impl_vm.dart b/cryptography/lib/src/dart/blake2b_impl_default.dart similarity index 100% rename from cryptography/lib/src/dart/blake2b_impl_vm.dart rename to cryptography/lib/src/dart/blake2b_impl_default.dart diff --git a/cryptography/lib/src/dart/blake2b_impl_browser.dart b/cryptography/lib/src/dart/blake2b_impl_js.dart similarity index 97% rename from cryptography/lib/src/dart/blake2b_impl_browser.dart rename to cryptography/lib/src/dart/blake2b_impl_js.dart index c383c913..2a4bfd3e 100644 --- a/cryptography/lib/src/dart/blake2b_impl_browser.dart +++ b/cryptography/lib/src/dart/blake2b_impl_js.dart @@ -324,8 +324,8 @@ class Blake2bSink extends DartHashSink with DartMacSinkMixin { { final low = vbLow ^ vcLow; final high = vbHigh ^ vcHigh; - vbLow = ((high << 8)) | low >> 24; - vbHigh = ((low << 8)) | high >> 24; + vbLow = (uint32mask & (high << 8)) | low >> 24; + vbHigh = (uint32mask & (low << 8)) | high >> 24; } // va = va + vb + m[y] @@ -339,8 +339,8 @@ class Blake2bSink extends DartHashSink with DartMacSinkMixin { { final low = vdLow ^ vaLow; final high = vdHigh ^ vaHigh; - vdLow = (high << 16) | low >> 16; - vdHigh = (low << 16) | high >> 16; + vdLow = (uint32mask & (high << 16)) | low >> 16; + vdHigh = (uint32mask & (low << 16)) | high >> 16; } // vc = c + d diff --git a/cryptography/lib/src/dart/rsa_pss.dart b/cryptography/lib/src/dart/rsa_pss.dart index 7db6f6df..75abc5c6 100644 --- a/cryptography/lib/src/dart/rsa_pss.dart +++ b/cryptography/lib/src/dart/rsa_pss.dart @@ -16,11 +16,9 @@ import 'dart:math'; import 'package:cryptography/cryptography.dart'; -/// [RsaPss] implementation in pure Dart. Currently it throws -/// [UnimplementedError] if you try to use it. +/// [RsaPss] algorithm written in Dart. /// -/// For examples and more information about the algorithm, see documentation for -/// the class [RsaPss]. +/// Currently it throws [UnimplementedError] if you try to use it. class DartRsaPss extends RsaPss { @override final HashAlgorithm hashAlgorithm; diff --git a/cryptography/lib/src/dart/rsa_ssa_pkcs1v15.dart b/cryptography/lib/src/dart/rsa_ssa_pkcs1v15.dart index 9c1a0f47..a9c8966a 100644 --- a/cryptography/lib/src/dart/rsa_ssa_pkcs1v15.dart +++ b/cryptography/lib/src/dart/rsa_ssa_pkcs1v15.dart @@ -16,11 +16,9 @@ import 'dart:math'; import 'package:cryptography/cryptography.dart'; -/// [DartRsaSsaPkcs1v15] implementation in pure Dart. Currently it throws -/// [UnimplementedError] if you try to use it. +/// [RsaSsaPkcs1v15] algorithm written in Dart. /// -/// For examples and more information about the algorithm, see documentation for -/// the class [Ecdh]. +/// Currently it throws [UnimplementedError] if you try to use it. class DartRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { @override final HashAlgorithm hashAlgorithm; diff --git a/cryptography/lib/src/dart/sha1.dart b/cryptography/lib/src/dart/sha1.dart index 9f759746..874bac92 100644 --- a/cryptography/lib/src/dart/sha1.dart +++ b/cryptography/lib/src/dart/sha1.dart @@ -19,7 +19,7 @@ import 'package:meta/meta.dart'; import '_helpers.dart'; -/// [Sha1] implemented by using in [package:crypto](https://pub.dev/packages/crypto) +/// [Sha1] implemented with [package:crypto](https://pub.dev/packages/crypto) /// (a package by Google). /// /// For examples and more information about the algorithm, see documentation for diff --git a/cryptography/lib/src/dart/sha256.dart b/cryptography/lib/src/dart/sha256.dart index bf0b3df5..df720065 100644 --- a/cryptography/lib/src/dart/sha256.dart +++ b/cryptography/lib/src/dart/sha256.dart @@ -20,7 +20,7 @@ import 'package:meta/meta.dart'; import '../../cryptography.dart'; import '../_internal/rotate.dart'; -/// A pure Dart implementation of [Sha224]. +/// [Sha224] algorithm written in Dart. /// /// For examples and more information about the algorithm, see documentation for /// the class [Sha224]. @@ -44,7 +44,7 @@ class DartSha224 extends Sha224 with DartHashAlgorithmMixin { } } -/// A pure Dart implementation of [Sha256]. +/// [Sha256] implemented with pure Dart. /// /// For examples and more information about the algorithm, see documentation for /// the class [Sha256]. diff --git a/cryptography/lib/src/dart/sha512.dart b/cryptography/lib/src/dart/sha512.dart index 26cc439a..f582f39c 100644 --- a/cryptography/lib/src/dart/sha512.dart +++ b/cryptography/lib/src/dart/sha512.dart @@ -19,7 +19,7 @@ import 'package:meta/meta.dart'; import '_helpers.dart'; -/// [Sha384] implemented by using in [package:crypto](https://pub.dev/packages/crypto) +/// [Sha384] implemented with [package:crypto](https://pub.dev/packages/crypto) /// (a package by Google). /// /// For examples and more information about the algorithm, see documentation for @@ -33,7 +33,7 @@ class DartSha384 extends Sha384 other.Hash get impl => other.sha384; } -/// [Sha512] implemented by using in [package:crypto](https://pub.dev/packages/crypto) +/// [Sha512] implemented with [package:crypto](https://pub.dev/packages/crypto) /// (a package by Google). /// /// For examples and more information about the algorithm, see documentation for diff --git a/cryptography/lib/src/helpers/random_bytes.dart b/cryptography/lib/src/helpers/random_bytes.dart index 6ce6a1a1..db013d03 100644 --- a/cryptography/lib/src/helpers/random_bytes.dart +++ b/cryptography/lib/src/helpers/random_bytes.dart @@ -20,7 +20,7 @@ import 'package:cryptography/helpers.dart'; import '../../cryptography.dart'; export 'random_bytes_impl_default.dart' - if (dart.library.html) 'random_bytes_impl_browser.dart'; + if (dart.library.js_interop) 'random_bytes_impl_browser.dart'; const _hexChars = [ '0', diff --git a/cryptography/lib/src/helpers/random_bytes_impl_browser.dart b/cryptography/lib/src/helpers/random_bytes_impl_browser.dart index 72501ccc..b4b2f43d 100644 --- a/cryptography/lib/src/helpers/random_bytes_impl_browser.dart +++ b/cryptography/lib/src/helpers/random_bytes_impl_browser.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:html' as html; +import 'dart:js_interop'; import 'dart:math'; import 'dart:typed_data'; @@ -20,15 +20,18 @@ import '../../cryptography.dart'; const _bit32 = 0x10000 * 0x10000; -// Store the function so it can't be mutated by Javascript libraries. -final _webCryptoRandom = html.window.crypto!.getRandomValues; - void fillBytesWithSecureRandom(Uint8List bytes, {Random? random}) { - if (random == null && - bytes.runtimeType == Uint8List && - BrowserCryptography.isSupported) { + if (random == null && BrowserCryptography.isSupported) { // Use Web Cryptography API directly (instead of Random.secure()). - _webCryptoRandom(bytes); + final jsArray = bytes.toJS; + _webCryptoRandom(jsArray); + final jsArrayToDart = jsArray.toDart; + if (!identical(jsArrayToDart, bytes)) { + for (var i = 0; i < bytes.length; i++) { + bytes[i] = jsArrayToDart[i]; + } + } + return; } random ??= SecureRandom.safe; for (var i = 0; i < bytes.length;) { @@ -47,3 +50,6 @@ void fillBytesWithSecureRandom(Uint8List bytes, {Random? random}) { } } } + +@JS('window.crypto.getRandomValues') +external void _webCryptoRandom(JSUint8Array buffer); diff --git a/cryptography/pubspec.yaml b/cryptography/pubspec.yaml index 7fdafac0..2b82d5b6 100644 --- a/cryptography/pubspec.yaml +++ b/cryptography/pubspec.yaml @@ -1,12 +1,12 @@ name: cryptography -version: 2.7.0 +version: 2.8.0 homepage: https://github.com/dint-dev/cryptography description: Cryptographic algorithms for encryption, digital signatures, key agreement, authentication, and - hashing. AES, Chacha20, ED25519, X25519, Argon2, and more. Good cross-platform support. + hashing. AES, Chacha20, ED25519, and more. Cross-platform (mobile, desktop, JS, WASM). environment: - sdk: '>=3.1.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' dependencies: # @@ -15,7 +15,6 @@ dependencies: collection: ^1.17.0 crypto: ^3.0.3 ffi: ^2.1.0 - js: ^0.6.7 meta: ^1.8.0 typed_data: ^1.3.0 @@ -23,5 +22,5 @@ dev_dependencies: # # Packages by Google: # - lints: ^2.1.1 + lints: '>=3.0.0 <7.0.0' test: ^1.24.0 diff --git a/cryptography/test/algorithms/argon2_test.dart b/cryptography/test/algorithms/argon2_test.dart index f1a949e5..52538322 100644 --- a/cryptography/test/algorithms/argon2_test.dart +++ b/cryptography/test/algorithms/argon2_test.dart @@ -287,39 +287,11 @@ void main() { final state = algorithm.newState(); expect(state.maxIsolates, maxIsolates); - final isJs = 1.0 is int; + final isJs = BrowserCryptography.isSupported; if (isJs) { expect(state.isolateCount, 0); } else { - switch (maxIsolates) { - case 0: - expect(state.isolateCount, 0); - break; - case 1: - expect(state.isolateCount, 1); - break; - case 2: - expect(state.isolateCount, 2); - break; - case 3: - expect(state.isolateCount, 3); - break; - case 4: - expect(state.isolateCount, 4); - break; - case 5: - expect(state.isolateCount, 4); - break; - case 6: - expect(state.isolateCount, 4); - break; - case 7: - expect(state.isolateCount, 4); - break; - case 8: - expect(state.isolateCount, 4); - break; - } + expect(state.isolateCount, maxIsolates.clamp(0, 4)); } final actual = await state.deriveKeyBytes( diff --git a/cryptography/test/algorithms/pbkdf2_test.dart b/cryptography/test/algorithms/pbkdf2_test.dart index ac6f6333..6ca798ec 100644 --- a/cryptography/test/algorithms/pbkdf2_test.dart +++ b/cryptography/test/algorithms/pbkdf2_test.dart @@ -44,10 +44,10 @@ void main() { } void _main() { - test('deriveKey(...): Hmac(sha256), 10k iterations in 300ms', () async { + test('deriveKey(...): Hmac(sha256), 10k iterations in 5s', () async { final macAlgorithm = Hmac.sha256(); - final n = 10 * 1000; - const maxDuration = Duration(milliseconds: 1000); + final n = 10000; + const maxDuration = Duration(seconds: 5); final pbkdf2 = Pbkdf2( macAlgorithm: macAlgorithm, diff --git a/cryptography/test/browser_cryptography_test.dart b/cryptography/test/browser_cryptography_test.dart index d08550f1..1c1f0595 100644 --- a/cryptography/test/browser_cryptography_test.dart +++ b/cryptography/test/browser_cryptography_test.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -@TestOn('chrome') +@TestOn('browser') library; import 'package:cryptography/cryptography.dart'; diff --git a/cryptography_flutter/CHANGELOG.md b/cryptography_flutter/CHANGELOG.md index 62e35439..7145af66 100644 --- a/cryptography_flutter/CHANGELOG.md +++ b/cryptography_flutter/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.3.3 +* Improves dependency constraints. + ## 2.3.2 * Improves documentation. diff --git a/cryptography_flutter/README.md b/cryptography_flutter/README.md index 5ee5c232..2d804913 100644 --- a/cryptography_flutter/README.md +++ b/cryptography_flutter/README.md @@ -7,7 +7,8 @@ This is a Flutter plugin that enables [pub.dev/packages/cryptography](https://pub.dev/packages/cryptography) to use native APIs of Android, iOS, and Mac OS X. -Maintained by [gohilla.com](https://gohilla.com). Licensed under the [Apache License 2.0](LICENSE). +Maintained by [terrier989](https://github.com/terrier989). +Licensed under the [Apache License 2.0](LICENSE). ## Why? * __Secure__ diff --git a/cryptography_flutter/lib/cryptography_flutter.dart b/cryptography_flutter/lib/cryptography_flutter.dart index 76ddfb9f..89547b4a 100644 --- a/cryptography_flutter/lib/cryptography_flutter.dart +++ b/cryptography_flutter/lib/cryptography_flutter.dart @@ -15,7 +15,8 @@ /// An optimized version of [package:cryptography](https://pub.dev/packages/cryptography). /// /// See [FlutterCryptography] for usage instructions. -library; +// ignore: unnecessary_library_name +library cryptography_flutter; import 'package:cryptography_flutter/cryptography_flutter.dart'; diff --git a/cryptography_flutter/pubspec.yaml b/cryptography_flutter/pubspec.yaml index 3257d56d..649396b8 100644 --- a/cryptography_flutter/pubspec.yaml +++ b/cryptography_flutter/pubspec.yaml @@ -2,11 +2,11 @@ name: cryptography_flutter description: Makes 'package:cryptography' use platform APIs in Android, iOS, and Mac OS X. The package can make performance up to 100 times better. -version: 2.3.2 +version: 2.3.3 homepage: https://github.com/dint-dev/cryptography environment: - sdk: '>=3.1.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' flutter: '>=3.13.0' # Open-source contributors: @@ -18,7 +18,7 @@ dependencies: # # Packages by github.com/dint-dev: # - cryptography: ^2.7.0 + cryptography: ^2.8.0 flutter: sdk: flutter @@ -26,7 +26,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.3 + flutter_lints: ^6.0.0 dependency_overrides: cryptography: diff --git a/cryptography_flutter_integration_test/pubspec.yaml b/cryptography_flutter_integration_test/pubspec.yaml index f824531e..93a2a42c 100644 --- a/cryptography_flutter_integration_test/pubspec.yaml +++ b/cryptography_flutter_integration_test/pubspec.yaml @@ -4,12 +4,12 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: '>=3.1.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' flutter: '>=3.13.0' dependencies: - cryptography: ^2.6.0 - cryptography_flutter: ^2.3.1 + cryptography: ^2.7.0 + cryptography_flutter: ^2.3.3 flutter: sdk: flutter cupertino_icons: ^1.0.2 @@ -20,7 +20,7 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter - flutter_lints: ^2.0.3 + flutter_lints: ^6.0.0 flutter: uses-material-design: true diff --git a/cryptography_test/dart_test.yaml b/cryptography_test/dart_test.yaml index cbaa1310..aee708a0 100644 --- a/cryptography_test/dart_test.yaml +++ b/cryptography_test/dart_test.yaml @@ -2,4 +2,5 @@ platforms: - vm - chrome compilers: + - dart2wasm - dart2js \ No newline at end of file diff --git a/cryptography_test/lib/algorithms/argon2.dart b/cryptography_test/lib/algorithms/argon2.dart index 2c937a4f..26a2c42e 100644 --- a/cryptography_test/lib/algorithms/argon2.dart +++ b/cryptography_test/lib/algorithms/argon2.dart @@ -20,6 +20,10 @@ import 'package:test/test.dart'; import '../hex.dart'; void testArgon2() { + if (BrowserCryptography.isRunningInWasm) { + // Password hashing tests take too long time in WASM. + return; + } group('$Argon2id:', () { test('memory=1MB parallelism=1 iterations=1', () async { final algorithm = Argon2id( diff --git a/cryptography_test/lib/algorithms/hkdf.dart b/cryptography_test/lib/algorithms/hkdf.dart index 82a15eea..ca030abe 100644 --- a/cryptography_test/lib/algorithms/hkdf.dart +++ b/cryptography_test/lib/algorithms/hkdf.dart @@ -19,116 +19,98 @@ import 'package:test/test.dart'; import '../hex.dart'; void testHkdf() { + if (BrowserCryptography.isRunningInWasm) { + // Password hashing tests take too long time in WASM. + return; + } group('Hkdf:', () { - group('${Cryptography.instance.runtimeType}:', () { - _main(); - }); - if (!identical(Cryptography.instance, DartCryptography.defaultInstance)) { - group('DartCryptography:', () { - setUp(() { - Cryptography.instance = DartCryptography.defaultInstance; - }); - _main(); - }); - } - if (BrowserCryptography.isSupported) { - group('BrowserCryptography:', () { - setUp(() { - Cryptography.instance = BrowserCryptography.defaultInstance; - }); - _main(); - }); - } - }); -} - -void _main() { - test('Test case #1: Hkdf-Hmac-Sha256', () async { - // Test vectors from RFC 5869: - // https://tools.ietf.org/html/rfc5869 + test('Test case #1: Hkdf-Hmac-Sha256', () async { + // Test vectors from RFC 5869: + // https://tools.ietf.org/html/rfc5869 - final secretKey = SecretKey(hexToBytes( - '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - )); - final nonce = hexToBytes( - '000102030405060708090a0b0c', - ); - final info = hexToBytes( - 'f0f1f2f3f4f5f6f7f8f9', - ); - const length = 42; - final expectedBytes = hexToBytes( - '3cb25f25faacd57a90434f64d0362f2a' - '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' - '34007208d5b887185865', - ); + final secretKey = SecretKey(hexToBytes( + '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + )); + final nonce = hexToBytes( + '000102030405060708090a0b0c', + ); + final info = hexToBytes( + 'f0f1f2f3f4f5f6f7f8f9', + ); + const length = 42; + final expectedBytes = hexToBytes( + '3cb25f25faacd57a90434f64d0362f2a' + '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' + '34007208d5b887185865', + ); - // End of test vectors + // End of test vectors - final hkdf = Hkdf( - hmac: Hmac(Sha256()), - outputLength: length, - ); - final actual = await hkdf.deriveKey( - secretKey: secretKey, - nonce: nonce, - info: info, - ); - expect( - hexFromBytes(actual.bytes), - hexFromBytes(expectedBytes), - ); - }); + final hkdf = Hkdf( + hmac: Hmac(Sha256()), + outputLength: length, + ); + final actual = await hkdf.deriveKey( + secretKey: secretKey, + nonce: nonce, + info: info, + ); + expect( + hexFromBytes(actual.bytes), + hexFromBytes(expectedBytes), + ); + }); - test('Test case #2: Hkdf-Hmac-Sha256', () async { - // Test vectors from RFC 5869: - // https://tools.ietf.org/html/rfc5869 + test('Test case #2: Hkdf-Hmac-Sha256', () async { + // Test vectors from RFC 5869: + // https://tools.ietf.org/html/rfc5869 - final secretKeyBytes = hexToBytes( - '000102030405060708090a0b0c0d0e0f' - '101112131415161718191a1b1c1d1e1f' - '202122232425262728292a2b2c2d2e2f' - '303132333435363738393a3b3c3d3e3f' - '404142434445464748494a4b4c4d4e4f', - ); - final nonce = hexToBytes( - '606162636465666768696a6b6c6d6e6f' - '707172737475767778797a7b7c7d7e7f' - '808182838485868788898a8b8c8d8e8f' - '909192939495969798999a9b9c9d9e9f' - 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf', - ); - final info = hexToBytes( - 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' - 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' - 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' - 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', - ); - const length = 82; - final expectedBytes = hexToBytes( - 'b11e398dc80327a1c8e7f78c596a4934' - '4f012eda2d4efad8a050cc4c19afa97c' - '59045a99cac7827271cb41c65e590e09' - 'da3275600c2f09b8367793a9aca3db71' - 'cc30c58179ec3e87c14c01d5c1f3434f' - '1d87', - ); + final secretKeyBytes = hexToBytes( + '000102030405060708090a0b0c0d0e0f' + '101112131415161718191a1b1c1d1e1f' + '202122232425262728292a2b2c2d2e2f' + '303132333435363738393a3b3c3d3e3f' + '404142434445464748494a4b4c4d4e4f', + ); + final nonce = hexToBytes( + '606162636465666768696a6b6c6d6e6f' + '707172737475767778797a7b7c7d7e7f' + '808182838485868788898a8b8c8d8e8f' + '909192939495969798999a9b9c9d9e9f' + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf', + ); + final info = hexToBytes( + 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' + 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' + 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' + 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', + ); + const length = 82; + final expectedBytes = hexToBytes( + 'b11e398dc80327a1c8e7f78c596a4934' + '4f012eda2d4efad8a050cc4c19afa97c' + '59045a99cac7827271cb41c65e590e09' + 'da3275600c2f09b8367793a9aca3db71' + 'cc30c58179ec3e87c14c01d5c1f3434f' + '1d87', + ); - // End of test vectors + // End of test vectors - final hkdf = Hkdf( - hmac: Hmac(Sha256()), - outputLength: length, - ); - final actual = await hkdf.deriveKey( - secretKey: SecretKey(secretKeyBytes), - nonce: nonce, - info: info, - ); - expect( - hexFromBytes(actual.bytes), - hexFromBytes(expectedBytes), - ); + final hkdf = Hkdf( + hmac: Hmac(Sha256()), + outputLength: length, + ); + final actual = await hkdf.deriveKey( + secretKey: SecretKey(secretKeyBytes), + nonce: nonce, + info: info, + ); + expect( + hexFromBytes(actual.bytes), + hexFromBytes(expectedBytes), + ); + }); }); } diff --git a/cryptography_test/lib/algorithms/pbkdf2.dart b/cryptography_test/lib/algorithms/pbkdf2.dart index e02ca499..f4a6873d 100644 --- a/cryptography_test/lib/algorithms/pbkdf2.dart +++ b/cryptography_test/lib/algorithms/pbkdf2.dart @@ -19,8 +19,12 @@ import 'package:test/scaffolding.dart'; import '../hex.dart'; void testPbkdf2() { + if (BrowserCryptography.isRunningInWasm) { + // Password hashing tests take too long time in WASM. + return; + } group('Pbkdf2:', () { - test('deriveKeyFromString(...): Hmac(sha256), 10000 iteration', () async { + test('deriveKeyFromString(...): Hmac(sha256), 10000 iterations', () async { const password = 'qwerty'; const nonce = [1, 2, 3]; final bits = 128; diff --git a/cryptography_test/lib/cryptography_test.dart b/cryptography_test/lib/cryptography_test.dart index d440ec30..c37e2ee1 100644 --- a/cryptography_test/lib/cryptography_test.dart +++ b/cryptography_test/lib/cryptography_test.dart @@ -64,16 +64,20 @@ import 'signature.dart'; /// Tests the current or the given [Cryptography]. void testCryptography({Cryptography? cryptography}) { - if (cryptography != null) { - group('$cryptography:', () { - setUpAll(() { - Cryptography.instance = cryptography; - }); - testCryptography(); - }); - return; + cryptography ??= Cryptography.instance; + var description = '${cryptography.runtimeType}'; + if (cryptography is BrowserCryptography) { + description = '$description (wasm: ${BrowserCryptography.isRunningInWasm})'; } + group('$description:', () { + setUp(() { + Cryptography.instance = cryptography!; + }); + _testCryptography(); + }); +} +void _testCryptography() { // Hash algorithms testBlake2s(); testBlake2b(); diff --git a/cryptography_test/pubspec.yaml b/cryptography_test/pubspec.yaml index e0c72f32..c01716ac 100644 --- a/cryptography_test/pubspec.yaml +++ b/cryptography_test/pubspec.yaml @@ -5,7 +5,7 @@ description: A package for testing and benchmarking cryptographic algorithm impl implement "package:cryptography" interfaces. environment: - sdk: '>=3.1.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' # Open-source contributors: # @@ -24,13 +24,13 @@ dependencies: # # Packages by github.com/dint-dev: # - cryptography: ^2.5.1 + cryptography: ^2.8.0 dev_dependencies: # # Packages by Google: # - lints: ^2.1.1 + lints: ^6.0.0 dependency_overrides: cryptography: diff --git a/jwk/CHANGELOG.md b/jwk/CHANGELOG.md index 25898ece..cadcec87 100644 --- a/jwk/CHANGELOG.md +++ b/jwk/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.2.5 +* Improves dependency constraints. + ## 0.2.4 * Improves documentation. diff --git a/jwk/dart_test.yaml b/jwk/dart_test.yaml index cbaa1310..aee708a0 100644 --- a/jwk/dart_test.yaml +++ b/jwk/dart_test.yaml @@ -2,4 +2,5 @@ platforms: - vm - chrome compilers: + - dart2wasm - dart2js \ No newline at end of file diff --git a/jwk/pubspec.yaml b/jwk/pubspec.yaml index b0b3b9e8..7310cf04 100644 --- a/jwk/pubspec.yaml +++ b/jwk/pubspec.yaml @@ -4,14 +4,14 @@ homepage: https://github.com/dint-dev/cryptography description: JWK (JSON Web Key) encoding and decoding (for package:cryptography). environment: - sdk: '>=3.1.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' dependencies: collection: ^1.17.0 - cryptography: ^2.6.0 + cryptography: ^2.8.0 dev_dependencies: - lints: ^2.1.1 + lints: '>=3.0.0 <7.0.0' test: ^1.24.0 dependency_overrides: