derive static method

Uint8List derive({
  1. required List<int> ikm,
  2. required int length,
  3. List<int> salt = const [],
  4. List<int> info = const [],
  5. String digest = 'SHA2-256',
})

HKDF-Extract-and-Expand with digest (OpenSSL name, default SHA2-256).

salt may be empty (RFC 5869 then uses a zero-filled salt), info may be empty. length is bounded by 255 × digest size.

Implementation

static Uint8List derive({
  required List<int> ikm,
  required int length,
  List<int> salt = const [],
  List<int> info = const [],
  String digest = 'SHA2-256',
}) {
  RangeError.checkNotNegative(length, 'length');
  if (length == 0) return Uint8List(0);
  initNoConfig();
  return using((arena) {
    final kdf = checkNotNull(
      ssl.EVP_KDF_fetch(nullptr, cString(arena, 'HKDF'), nullptr),
      'EVP_KDF_fetch(HKDF)',
    );
    arena.onReleaseAll(() => ssl.EVP_KDF_free(kdf));
    final ctx = checkNotNull(ssl.EVP_KDF_CTX_new(kdf), 'EVP_KDF_CTX_new');
    arena.onReleaseAll(() => ssl.EVP_KDF_CTX_free(ctx));

    final bld = checkNotNull(ssl.OSSL_PARAM_BLD_new(), 'OSSL_PARAM_BLD_new');
    arena.onReleaseAll(() => ssl.OSSL_PARAM_BLD_free(bld));
    checkOne(
      ssl.OSSL_PARAM_BLD_push_utf8_string(
        bld,
        cString(arena, 'digest'),
        cString(arena, digest),
        0,
      ),
      'OSSL_PARAM_BLD_push_utf8_string(digest)',
    );
    checkOne(
      ssl.OSSL_PARAM_BLD_push_octet_string(
        bld,
        cString(arena, 'key'),
        secretToNative(arena, ikm).cast(),
        ikm.length,
      ),
      'OSSL_PARAM_BLD_push_octet_string(key)',
    );
    if (salt.isNotEmpty) {
      checkOne(
        ssl.OSSL_PARAM_BLD_push_octet_string(
          bld,
          cString(arena, 'salt'),
          toNative(arena, salt).cast(),
          salt.length,
        ),
        'OSSL_PARAM_BLD_push_octet_string(salt)',
      );
    }
    if (info.isNotEmpty) {
      checkOne(
        ssl.OSSL_PARAM_BLD_push_octet_string(
          bld,
          cString(arena, 'info'),
          toNative(arena, info).cast(),
          info.length,
        ),
        'OSSL_PARAM_BLD_push_octet_string(info)',
      );
    }
    final params = checkNotNull(
      ssl.OSSL_PARAM_BLD_to_param(bld),
      'OSSL_PARAM_BLD_to_param',
    );
    arena.onReleaseAll(() => ssl.OSSL_PARAM_free(params));

    final out = secretBuffer(arena, length);
    checkOne(
      ssl.EVP_KDF_derive(ctx, out, length, params),
      'EVP_KDF_derive(HKDF)',
    );
    return fromNative(out, length);
  });
}