From 51c520c096ebf60ae00f3318eb0767768fa0c2a4 Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Sat, 9 Nov 2024 04:44:51 +0530 Subject: [PATCH 1/7] refactor: update fill-random-bytes --- lib/src/impl_ffi/impl_ffi.dart | 3 ++ lib/src/impl_ffi/impl_ffi.random.dart | 25 ++++++---- lib/src/impl_interface/impl_interface.dart | 2 + .../impl_interface/impl_interface.random.dart | 19 ++++++++ lib/src/impl_js/impl_js.dart | 3 ++ lib/src/impl_js/impl_js.random.dart | 15 ++++-- lib/src/impl_stub.dart | 47 ------------------- lib/src/impl_stub/impl_stub.dart | 4 ++ lib/src/impl_stub/impl_stub.ecdsa.dart | 4 +- lib/src/impl_stub/impl_stub.random.dart | 24 ++++++++++ lib/src/webcrypto/webcrypto.dart | 3 -- lib/src/webcrypto/webcrypto.random.dart | 2 +- test/crypto_subtle_test.dart | 6 +-- 13 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 lib/src/impl_interface/impl_interface.random.dart delete mode 100644 lib/src/impl_stub.dart create mode 100644 lib/src/impl_stub/impl_stub.random.dart diff --git a/lib/src/impl_ffi/impl_ffi.dart b/lib/src/impl_ffi/impl_ffi.dart index cbcb64bb..84db8242 100644 --- a/lib/src/impl_ffi/impl_ffi.dart +++ b/lib/src/impl_ffi/impl_ffi.dart @@ -122,4 +122,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 e4f25060..a5a2db27 100644 --- a/lib/src/impl_interface/impl_interface.dart +++ b/lib/src/impl_interface/impl_interface.dart @@ -29,6 +29,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 { @@ -99,4 +100,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..2878ee1b --- /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 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 3d24d93a..f3e3624d 100644 --- a/lib/src/impl_js/impl_js.dart +++ b/lib/src/impl_js/impl_js.dart @@ -109,4 +109,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 7298cab2..07dd2678 100644 --- a/lib/src/impl_js/impl_js.random.dart +++ b/lib/src/impl_js/impl_js.random.dart @@ -14,10 +14,15 @@ part of 'impl_js.dart'; -void fillRandomBytes(TypedData destination) { - try { - subtle.getRandomValues(destination); - } on subtle.JSDomException catch (e) { - throw _translateDomException(e); +final class _RandomImpl implements RandomImpl { + const _RandomImpl(); + + @override + void fillRandomBytes(TypedData destination) { + try { + subtle.getRandomValues(destination); + } on subtle.JSDomException catch (e) { + throw _translateDomException(e); + } } } 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 d6bf9dc0..ff3b8405 100644 --- a/lib/src/webcrypto/webcrypto.dart +++ b/lib/src/webcrypto/webcrypto.dart @@ -25,9 +25,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) '../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) '../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 2d3db92f..f4a8ac6c 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -30,7 +30,7 @@ void main() { data.every((e) => e == 0), isTrue, ); - fillRandomBytes(data); + webCryptImpl.random.fillRandomBytes(data); expect( data.any((e) => e != 0), isTrue, @@ -39,7 +39,7 @@ void main() { test('Uint8List: too long', () { expect( - () => fillRandomBytes(Uint8List(1000000)), + () => webCryptImpl.random.fillRandomBytes(Uint8List(1000000)), throwsA( isA(), ), @@ -48,7 +48,7 @@ void main() { test('Uint64List: not supported type', () { expect( - () => fillRandomBytes(Uint64List(32)), + () => webCryptImpl.random.fillRandomBytes(Uint64List(32)), throwsA( isA(), ), From d56a651911954b24db271eeb7f487b7fefa1236e Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil <96776914+HamdaanAliQuatil@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:59:11 +0530 Subject: [PATCH 2/7] Update lib/src/impl_interface/impl_interface.random.dart Co-authored-by: Jonas Finnemann Jensen --- lib/src/impl_interface/impl_interface.random.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/impl_interface/impl_interface.random.dart b/lib/src/impl_interface/impl_interface.random.dart index 2878ee1b..f6c0e9a9 100644 --- a/lib/src/impl_interface/impl_interface.random.dart +++ b/lib/src/impl_interface/impl_interface.random.dart @@ -14,6 +14,6 @@ part of 'impl_interface.dart'; -abstract class RandomImpl { +abstract interface class RandomImpl { void fillRandomBytes(TypedData destination); } From 9081842e87fd2b7c2ab5377904fa1b585f2dd27d Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Fri, 22 Nov 2024 22:58:49 +0530 Subject: [PATCH 3/7] fix: replace webcrypt with subtle.window --- test/crypto_subtle_test.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index f4a8ac6c..bf7fa24d 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -20,7 +20,6 @@ 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'; void main() { group('fillRandomBytes', () { @@ -30,7 +29,7 @@ void main() { data.every((e) => e == 0), isTrue, ); - webCryptImpl.random.fillRandomBytes(data); + subtle.window.crypto.getRandomValues(data.toJS); expect( data.any((e) => e != 0), isTrue, @@ -39,7 +38,7 @@ void main() { test('Uint8List: too long', () { expect( - () => webCryptImpl.random.fillRandomBytes(Uint8List(1000000)), + () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), throwsA( isA(), ), @@ -48,7 +47,7 @@ void main() { test('Uint64List: not supported type', () { expect( - () => webCryptImpl.random.fillRandomBytes(Uint64List(32)), + () => subtle.window.crypto.getRandomValues(Uint8List.view(Uint64List(32).buffer).toJS), throwsA( isA(), ), From 6b9d5ec6ced17fdd5eb36bd2d1bd56b5849ab433 Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Fri, 22 Nov 2024 23:05:32 +0530 Subject: [PATCH 4/7] fix: update uint8list: too long test values --- test/crypto_subtle_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index bf7fa24d..dc571180 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -38,7 +38,7 @@ void main() { test('Uint8List: too long', () { expect( - () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), + () => subtle.window.crypto.getRandomValues(Uint8List(65536).toJS), throwsA( isA(), ), From e43d1a29dda724adfa2e612444c81c52e728ddce Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Fri, 22 Nov 2024 23:42:44 +0530 Subject: [PATCH 5/7] tests: update test error details --- test/crypto_subtle_test.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index dc571180..e2e44030 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -38,9 +38,13 @@ void main() { test('Uint8List: too long', () { expect( - () => subtle.window.crypto.getRandomValues(Uint8List(65536).toJS), + () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), throwsA( - isA(), + isA().having( + (e) => e.name, + 'name', + 'QuotaExceededError', + ), ), ); }); From 854ba62c352aeb8b149123add7bb35db34d4a175 Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Fri, 22 Nov 2024 23:51:55 +0530 Subject: [PATCH 6/7] refactor: format dart code --- test/crypto_subtle_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index e2e44030..4396f890 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -51,7 +51,8 @@ void main() { test('Uint64List: not supported type', () { expect( - () => subtle.window.crypto.getRandomValues(Uint8List.view(Uint64List(32).buffer).toJS), + () => subtle.window.crypto + .getRandomValues(Uint8List.view(Uint64List(32).buffer).toJS), throwsA( isA(), ), From d44ae995a36f4c6fe2b3b6936608736688ec8b3e Mon Sep 17 00:00:00 2001 From: HamdaanAliQuatil Date: Mon, 2 Dec 2024 14:28:12 +0530 Subject: [PATCH 7/7] fix: update tests in group crypto --- test/crypto_subtle_test.dart | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index 4396f890..1d182359 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -20,6 +20,7 @@ import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:webcrypto/src/crypto_subtle.dart' as subtle; +import 'package:webcrypto/webcrypto.dart'; void main() { group('fillRandomBytes', () { @@ -29,7 +30,7 @@ void main() { data.every((e) => e == 0), isTrue, ); - subtle.window.crypto.getRandomValues(data.toJS); + fillRandomBytes(data); expect( data.any((e) => e != 0), isTrue, @@ -38,21 +39,16 @@ void main() { test('Uint8List: too long', () { expect( - () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), + () => fillRandomBytes(Uint8List(1000000)), throwsA( - isA().having( - (e) => e.name, - 'name', - 'QuotaExceededError', - ), + isA(), ), ); }); test('Uint64List: not supported type', () { expect( - () => subtle.window.crypto - .getRandomValues(Uint8List.view(Uint64List(32).buffer).toJS), + () => fillRandomBytes(Uint64List(32)), throwsA( isA(), ), @@ -67,7 +63,7 @@ void main() { data.every((e) => e == 0), isTrue, ); - subtle.window.crypto.getRandomValues(data.toJS); + fillRandomBytes(data); expect( data.any((e) => e != 0), isTrue, @@ -76,26 +72,18 @@ void main() { test('getRandomValues: too long', () { expect( - () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), + () => fillRandomBytes(Uint8List(1000000)), throwsA( - isA().having( - (e) => e.name, - 'name', - 'QuotaExceededError', - ), + isA(), ), ); }); test('getRandomValues: not supported type', () { expect( - () => subtle.window.crypto.getRandomValues(Float32List(32).toJS), + () => fillRandomBytes(Uint64List(32)), throwsA( - isA().having( - (e) => e.name, - 'name', - 'TypeMismatchError', - ), + isA(), ), ); });