Skip to content

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

Description

@harrshita123

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

import 'package:webcrypto/webcrypto.dart';

Future<void> main() async {
  for (final entry in <String, Hash>{
    '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:

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:

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions