google / google/webcrypto.dart
bug: native HMAC generation uses digest size instead of hash block size by default
- Dominant language
- Dart
- Stars
- 116
- Forks
- 110
- Avg merge
- 6d 8h
- Merged PRs (30d)
- 9
Description
### Description
`HmacSecretKey.generateKey(hash)` produces different default key lengths on native and browser backends.
When `length` is omitted, Web Crypto requires the recommended HMAC key length to be the block size of the selected hash function. The browser backend delegates this choice to `SubtleCrypto.generateKey` and follows that rule, but the FFI backend uses `EVP_MD_size`, which is the digest size rather than the block size.
This gives the following results:
| Hash | FFI backend | Web Crypto / browser |
| --- | ---: | ---: |
| SHA-1 | 160 bits | 512 bits |
| SHA-256 | 256 bits | 512 bits |
| SHA-384 | 384 bits | 1024 bits |
| SHA-512 | 512 bits | 1024 bits |
The public documentation currently describes the FFI behavior, so it also differs from Web Crypto's definition.
### Reproduction
```dart
import 'package:webcrypto/webcrypto.dart';
Future main() async {
for (final entry in {
'SHA-1': Hash.sha1,
'SHA-256': Hash.sha256,
'SHA-384': Hash.sha384,
'SHA-512': Hash.sha512,
}.entries) {
final key = await HmacSecretKey.generateKey(entry.value);
final raw = await key.exportRawKey();
print('${entry.key}: ${raw.length * 8} bits');
}
}
```
On the FFI backend this prints:
```text
SHA-1: 160 bits
SHA-256: 256 bits
SHA-384: 384 bits
SHA-512: 512 bits
```
### Expected behavior
Omitting `length` should generate a key whose length equals the hash function's block size:
- 512 bits for SHA-1 and SHA-256
- 1024 bits for SHA-384 and SHA-512
An explicitly supplied `length` should continue to take precedence unchanged.
This matches the HMAC key generation algorithm in the Web Cryptography specification:
https://www.w3.org/TR/WebCryptoAPI/#hmac-operations
### Actual behavior
The FFI implementation defaults to:
```dart
length ??= ssl.EVP_MD_size(h._md) * 8;
```
`EVP_MD_size` returns the digest size, causing native-generated keys to be shorter than browser-generated keys for every supported hash.
### Suggested fix
- Represent the HMAC default block size for each supported hash in the native implementation.
- Use it only when `length` is omitted.
- Correct the `HmacSecretKey.generateKey` documentation.
- Add regression coverage for all supported hashes and for an explicit length.
Contributor guide
Research direction
Start at the native FFI implementation of HmacSecretKey.generateKey and inspect the EVP_MD_size defaulting path described in the issue. Review the HmacSecretKey.generateKey documentation and add regression coverage for every supported hash plus an explicit length. Done means omitted lengths match each hash's Web Crypto block-size default while explicit lengths remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100