google / google/webcrypto.dart

bug: native HMAC generation uses digest size instead of hash block size by default

Open
#342 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.