From cd9bbdbc8f40492f35d6b752ee9ae809ccb2bf9a Mon Sep 17 00:00:00 2001 From: Harshita Yadav Date: Wed, 12 Aug 2026 14:25:09 +0530 Subject: [PATCH 1/2] fix(hmac): reject empty imported keys --- lib/src/impl_ffi/impl_ffi.hmac.dart | 1 + test/hmac_empty_key_test.dart | 47 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/hmac_empty_key_test.dart diff --git a/lib/src/impl_ffi/impl_ffi.hmac.dart b/lib/src/impl_ffi/impl_ffi.hmac.dart index 71780f08..35e9ebe8 100644 --- a/lib/src/impl_ffi/impl_ffi.hmac.dart +++ b/lib/src/impl_ffi/impl_ffi.hmac.dart @@ -37,6 +37,7 @@ Future hmacSecretKey_importRawKey( HashImpl hash, { int? length, }) async { + _checkData(keyData.isNotEmpty, message: 'HMAC key data must not be empty'); return _HmacSecretKeyImpl( _asUint8ListZeroedToBitLength(keyData, length), _HashImpl.fromHash(hash), diff --git a/test/hmac_empty_key_test.dart b/test/hmac_empty_key_test.dart new file mode 100644 index 00000000..fa920ccb --- /dev/null +++ b/test/hmac_empty_key_test.dart @@ -0,0 +1,47 @@ +// Copyright 2026 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. + +@TestOn('vm') +library; + +import 'package:test/test.dart'; +import 'package:webcrypto/webcrypto.dart'; + +final _throwsEmptyKey = throwsA( + isA().having( + (error) => error.message, + 'message', + 'HMAC key data must not be empty', + ), +); + +void main() { + test('rejects an empty raw key', () async { + await expectLater( + HmacSecretKey.importRawKey(const [], Hash.sha256), + _throwsEmptyKey, + ); + }); + + test('rejects an empty JWK key', () async { + await expectLater( + HmacSecretKey.importJsonWebKey(const { + 'kty': 'oct', + 'alg': 'HS256', + 'k': '', + }, Hash.sha256), + _throwsEmptyKey, + ); + }); +} From d4e036f9991c33305cd5240a059b8cc709d2c584 Mon Sep 17 00:00:00 2001 From: Harshita Yadav Date: Wed, 12 Aug 2026 19:28:54 +0530 Subject: [PATCH 2/2] test(hmac): run empty-key regression across platforms --- .../testing/regression/hmac_empty_key.dart | 46 ++++++++++--------- lib/src/testing/testing.dart | 2 + 2 files changed, 26 insertions(+), 22 deletions(-) rename test/hmac_empty_key_test.dart => lib/src/testing/regression/hmac_empty_key.dart (57%) diff --git a/test/hmac_empty_key_test.dart b/lib/src/testing/regression/hmac_empty_key.dart similarity index 57% rename from test/hmac_empty_key_test.dart rename to lib/src/testing/regression/hmac_empty_key.dart index fa920ccb..1c2c0422 100644 --- a/test/hmac_empty_key_test.dart +++ b/lib/src/testing/regression/hmac_empty_key.dart @@ -12,36 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -@TestOn('vm') -library; - -import 'package:test/test.dart'; import 'package:webcrypto/webcrypto.dart'; -final _throwsEmptyKey = throwsA( - isA().having( - (error) => error.message, - 'message', - 'HMAC key data must not be empty', - ), -); +import '../utils/utils.dart'; -void main() { - test('rejects an empty raw key', () async { - await expectLater( +List<({String name, Future Function() test})> tests() => [ + ( + name: 'HMAC rejects empty raw keys', + test: () => _expectEmptyKeyRejected( HmacSecretKey.importRawKey(const [], Hash.sha256), - _throwsEmptyKey, - ); - }); - - test('rejects an empty JWK key', () async { - await expectLater( + ), + ), + ( + name: 'HMAC rejects empty JWK keys', + test: () => _expectEmptyKeyRejected( HmacSecretKey.importJsonWebKey(const { 'kty': 'oct', 'alg': 'HS256', 'k': '', }, Hash.sha256), - _throwsEmptyKey, + ), + ), +]; + +Future _expectEmptyKeyRejected(Future import) async { + try { + await import; + } on FormatException catch (error) { + check( + error.message == 'HMAC key data must not be empty', + 'Expected an empty HMAC key error', ); - }); + return; + } + check(false, 'Expected an empty HMAC key to be rejected'); } diff --git a/lib/src/testing/testing.dart b/lib/src/testing/testing.dart index 21db1cb5..6f487de9 100644 --- a/lib/src/testing/testing.dart +++ b/lib/src/testing/testing.dart @@ -31,6 +31,7 @@ import 'webcrypto/rsassapkcs1v15.dart' as rsassapkcs1v15; import 'webcrypto/random.dart' as random; import 'webcrypto/digest.dart' as digest; import 'regression/derive_bits_zero_length.dart' as derive_bits_zero_length; +import 'regression/hmac_empty_key.dart' as hmac_empty_key; import 'regression/issue_60_trailing_bytes.dart' as issue_60_trailing_bytes; import 'regression/rsa_oaep_sha1_jwk_alg.dart' as rsa_oaep_sha1_jwk_alg; @@ -63,6 +64,7 @@ void runAllTests( ...digest.tests(), ...issue_60_trailing_bytes.tests(), ...derive_bits_zero_length.tests(), + ...hmac_empty_key.tests(), ...rsa_oaep_sha1_jwk_alg.tests(), ];