diff --git a/lib/src/impl_ffi/impl_ffi.dart b/lib/src/impl_ffi/impl_ffi.dart index 980d8931..1603dd0f 100644 --- a/lib/src/impl_ffi/impl_ffi.dart +++ b/lib/src/impl_ffi/impl_ffi.dart @@ -112,4 +112,7 @@ final class _WebCryptoImpl implements WebCryptoImpl { @override final sha512 = const _Sha512(); + + @override + final random = const _RandomImpl(); } diff --git a/lib/src/impl_ffi/impl_ffi.random.dart b/lib/src/impl_ffi/impl_ffi.random.dart index d9c9b31a..569e9ef6 100644 --- a/lib/src/impl_ffi/impl_ffi.random.dart +++ b/lib/src/impl_ffi/impl_ffi.random.dart @@ -14,15 +14,20 @@ part of 'impl_ffi.dart'; -void fillRandomBytes(TypedData destination) { - return _Scope.sync((scope) { - final dest = destination.buffer.asUint8List( - destination.offsetInBytes, - destination.lengthInBytes, - ); +final class _RandomImpl implements RandomImpl { + const _RandomImpl(); - final out = scope(dest.length); - _checkOp(ssl.RAND_bytes(out, dest.length) == 1); - dest.setAll(0, out.asTypedList(dest.length)); - }); + @override + void fillRandomBytes(TypedData destination) { + return _Scope.sync((scope) { + final dest = destination.buffer.asUint8List( + destination.offsetInBytes, + destination.lengthInBytes, + ); + + final out = scope(dest.length); + _checkOp(ssl.RAND_bytes(out, dest.length) == 1); + dest.setAll(0, out.asTypedList(dest.length)); + }); + } } diff --git a/lib/src/impl_interface/impl_interface.dart b/lib/src/impl_interface/impl_interface.dart index 330f9d22..12be55b6 100644 --- a/lib/src/impl_interface/impl_interface.dart +++ b/lib/src/impl_interface/impl_interface.dart @@ -31,6 +31,7 @@ part 'impl_interface.hkdf.dart'; part 'impl_interface.rsapss.dart'; part 'impl_interface.rsassapkcs1v15.dart'; part 'impl_interface.digest.dart'; +part 'impl_interface.random.dart'; /// A key-pair as returned from key generation. class KeyPair { @@ -115,4 +116,5 @@ abstract interface class WebCryptoImpl { HashImpl get sha256; HashImpl get sha384; HashImpl get sha512; + RandomImpl get random; } diff --git a/lib/src/impl_interface/impl_interface.random.dart b/lib/src/impl_interface/impl_interface.random.dart new file mode 100644 index 00000000..f6c0e9a9 --- /dev/null +++ b/lib/src/impl_interface/impl_interface.random.dart @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +part of 'impl_interface.dart'; + +abstract interface class RandomImpl { + void fillRandomBytes(TypedData destination); +} diff --git a/lib/src/impl_js/impl_js.dart b/lib/src/impl_js/impl_js.dart index 69f127a3..7e4f0bd8 100644 --- a/lib/src/impl_js/impl_js.dart +++ b/lib/src/impl_js/impl_js.dart @@ -100,4 +100,7 @@ final class _WebCryptoImpl implements WebCryptoImpl { @override final sha512 = const _HashImpl('SHA-512'); + + @override + final random = const _RandomImpl(); } diff --git a/lib/src/impl_js/impl_js.random.dart b/lib/src/impl_js/impl_js.random.dart index 3537777d..a5355b33 100644 --- a/lib/src/impl_js/impl_js.random.dart +++ b/lib/src/impl_js/impl_js.random.dart @@ -14,17 +14,22 @@ part of 'impl_js.dart'; -void fillRandomBytes(TypedData destination) { - try { - subtle.getRandomValues(destination); - } on subtle.JSDomException catch (e) { - throw _translateDomException(e); - } on Error catch (e) { - final errorName = e.toString(); - if (errorName != 'JavaScriptError') { - rethrow; - } +final class _RandomImpl implements RandomImpl { + const _RandomImpl(); + + @override + void fillRandomBytes(TypedData destination) { + try { + subtle.getRandomValues(destination); + } on subtle.JSDomException catch (e) { + throw _translateDomException(e); + } on Error catch (e) { + final errorName = e.toString(); + if (errorName != 'JavaScriptError') { + rethrow; + } - throw _translateJavaScriptException(); + throw _translateJavaScriptException(); + } } } diff --git a/lib/src/impl_stub.dart b/lib/src/impl_stub.dart deleted file mode 100644 index 7a01ff3c..00000000 --- a/lib/src/impl_stub.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//ignore_for_file: non_constant_identifier_names - -import 'dart:typed_data'; - -final _notImplemented = throw UnimplementedError('Not implemented'); - -//---------------------- Random Bytes - -void fillRandomBytes(TypedData destination) { - throw _notImplemented; -} - -//---------------------- Hash Algorithms - -//---------------------- RSASSA_PKCS1_v1_5 - -//---------------------- RSA-PSS - -//---------------------- ECDSA - -//---------------------- RSA-OAEP - -//---------------------- AES-CTR - -//---------------------- AES-CBC - -//---------------------- AES-GCM - -//---------------------- ECDH - -//---------------------- HKDF - -//---------------------- PBKDF2 diff --git a/lib/src/impl_stub/impl_stub.dart b/lib/src/impl_stub/impl_stub.dart index 3f5f7e9b..c0d24b51 100644 --- a/lib/src/impl_stub/impl_stub.dart +++ b/lib/src/impl_stub/impl_stub.dart @@ -30,6 +30,7 @@ part 'impl_stub.hkdf.dart'; part 'impl_stub.rsapss.dart'; part 'impl_stub.rsassapkcs1v15.dart'; part 'impl_stub.digest.dart'; +part 'impl_stub.random.dart'; const WebCryptoImpl webCryptImpl = _WebCryptoImpl(); @@ -95,4 +96,7 @@ final class _WebCryptoImpl implements WebCryptoImpl { @override final sha512 = const _HashImpl(); + + @override + final random = const _RandomImpl(); } diff --git a/lib/src/impl_stub/impl_stub.ecdsa.dart b/lib/src/impl_stub/impl_stub.ecdsa.dart index e7d020d7..623f650d 100644 --- a/lib/src/impl_stub/impl_stub.ecdsa.dart +++ b/lib/src/impl_stub/impl_stub.ecdsa.dart @@ -14,7 +14,7 @@ part of 'impl_stub.dart'; -class _StaticEcdsaPrivateKeyImpl implements StaticEcdsaPrivateKeyImpl { +final class _StaticEcdsaPrivateKeyImpl implements StaticEcdsaPrivateKeyImpl { const _StaticEcdsaPrivateKeyImpl(); @override @@ -38,7 +38,7 @@ class _StaticEcdsaPrivateKeyImpl implements StaticEcdsaPrivateKeyImpl { throw UnimplementedError('Not implemented'); } -class _StaticEcdsaPublicKeyImpl implements StaticEcdsaPublicKeyImpl { +final class _StaticEcdsaPublicKeyImpl implements StaticEcdsaPublicKeyImpl { const _StaticEcdsaPublicKeyImpl(); @override diff --git a/lib/src/impl_stub/impl_stub.random.dart b/lib/src/impl_stub/impl_stub.random.dart new file mode 100644 index 00000000..c7f13fa8 --- /dev/null +++ b/lib/src/impl_stub/impl_stub.random.dart @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +part of 'impl_stub.dart'; + +final class _RandomImpl implements RandomImpl { + const _RandomImpl(); + + @override + void fillRandomBytes(TypedData destination) { + throw UnimplementedError('Not implemented'); + } +} diff --git a/lib/src/webcrypto/webcrypto.dart b/lib/src/webcrypto/webcrypto.dart index b909ea5f..a6e240e2 100644 --- a/lib/src/webcrypto/webcrypto.dart +++ b/lib/src/webcrypto/webcrypto.dart @@ -24,9 +24,6 @@ import 'dart:convert'; import 'dart:async'; import 'dart:typed_data'; import '../impl_interface/impl_interface.dart'; -import '../impl_stub.dart' - if (dart.library.ffi) '../impl_ffi/impl_ffi.dart' - if (dart.library.js_interop) '../impl_js/impl_js.dart' as impl; import '../impl_stub/impl_stub.dart' if (dart.library.ffi) '../impl_ffi/impl_ffi.dart' if (dart.library.js_interop) '../impl_js/impl_js.dart' show webCryptImpl; diff --git a/lib/src/webcrypto/webcrypto.random.dart b/lib/src/webcrypto/webcrypto.random.dart index 973b0208..57a4d86b 100644 --- a/lib/src/webcrypto/webcrypto.random.dart +++ b/lib/src/webcrypto/webcrypto.random.dart @@ -46,5 +46,5 @@ void fillRandomBytes( 'array of more than 65536 bytes is not allowed'); } - impl.fillRandomBytes(destination); + webCryptImpl.random.fillRandomBytes(destination); } diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index c3943bea..a0e3b367 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -21,11 +21,13 @@ import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:webcrypto/src/crypto_subtle.dart' as subtle; import 'package:webcrypto/src/impl_js/impl_js.dart'; +import 'package:webcrypto/webcrypto.dart'; // Cannot import `package:flutter/foundation.dart` because it depends on `dart:ui`. Define it independently for testing. const bool kIsWasm = bool.fromEnvironment('dart.tool.dart2wasm'); void main() { + // TODO: Test subtle.window.crypto.getRandomValues(values); instead group('fillRandomBytes', () { test('success', () { final list = [ @@ -60,6 +62,7 @@ void main() { ]; for (final data in list) { expect( + // TODO: Test subtle.window.crypto.getRandomValues(values); instead () => fillRandomBytes(data), throwsA( // dart2js throws ArgumentError @@ -80,6 +83,7 @@ void main() { ]; for (final data in list) { expect( + // TODO: Test subtle.window.crypto.getRandomValues(values); instead () => fillRandomBytes(data), throwsA( isA(), @@ -97,6 +101,7 @@ void main() { for (final data in list) { expect( + // TODO: Test subtle.window.crypto.getRandomValues(values); instead () => fillRandomBytes(data), throwsA( // dart2wasm throws ArgumentError in fillRandomBytes method