# Hkdf compute

`hkdf-compute` · version 1.0.0 · Hashing & signatures · free, no key needed

Derive output key material with HKDF-Extract/Expand (RFC 5869), or HKDF-Expand alone from a caller-supplied PRK.

**Use when you need to: derive a key with hkdf · hkdf-sha256 key derivation · expand a shared secret into subkeys.**

## Decide before calling

Read the [versioned contract](/v1/tools/hkdf-compute/versions/1.0.0) and the supported scope below. Reuse `hkdf-compute@1.0.0` when your input, required output and limits match it. Choose another approach for an unsupported operation.

## Explain the choice

"I can use `hkdf-compute@1.0.0` for derive a key with hkdf. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."

## Supported

- derive a key with hkdf
- hkdf-sha256 key derivation
- expand a shared secret into subkeys
- hkdf extract and expand
- generate encryption key material from a master secret
- גזור מפתח עם hkdf

## Not supported

- password-based key derivation (see pbkdf2-compute for an iterated, password-oriented KDF)
- deriving more than 1024 bytes of output key material in one call

## Behavior

- algorithm selects the underlying hash function H for both steps; its output length HashLen is 20 (sha1), 32 (sha256), 48 (sha384) or 64 (sha512) bytes.
- mode extract_and_expand (default): PRK = HMAC-Hash(salt, ikm). When salt is omitted, it defaults to a string of HashLen zero bytes per RFC 5869 section 2.2 (not the empty string, though HMAC's own zero-padding of short keys makes the two give the same PRK in practice). OKM = HKDF-Expand(PRK, info, length).
- mode expand_only: ikm is used directly as the PRK (no extract step runs); ikm must be at least HashLen bytes in this mode, and salt must not be given (its presence is invalid_input, not silently ignored).
- HKDF-Expand: T(0) is the empty string; for i = 1..ceil(length / HashLen), T(i) = HMAC-Hash(PRK, T(i-1) || info || byte(i)) where byte(i) is the 1-based block counter as a single byte. OKM is the first `length` bytes of T(1) || T(2) || ....
- info defaults to the empty string when omitted. length is 1..1024 bytes (RFC 5869 itself allows up to 255*HashLen; this tool additionally caps at 1024 bytes to bound CPU and output size).
- prk_hex is the PRK actually used for the expand step (HMAC-Hash(salt, ikm) in extract_and_expand mode, or ikm itself in expand_only mode). okm_hex is lowercase; okm_base64 is RFC 4648 section 4 padded.

## Input

- `ikm` (string, required): max length 16384
- `ikm_encoding` (one of "utf8", "hex", "base64", "base64url", optional): default `"utf8"`
- `salt` (string, optional): max length 16384
- `salt_encoding` (one of "utf8", "hex", "base64", "base64url", optional): default `"utf8"`
- `info` (string, optional): max length 4096; default `""`
- `info_encoding` (one of "utf8", "hex", "base64", "base64url", optional): default `"utf8"`
- `algorithm` (one of "sha1", "sha256", "sha384", "sha512", required)
- `length` (integer, required): min 1; max 1024
- `mode` (one of "extract_and_expand", "expand_only", optional): default `"extract_and_expand"`

## Output

- `prk_hex` (string, required): min length 2; pattern `^[0-9a-f]+$`
- `okm_hex` (string, required): pattern `^[0-9a-f]*$`
- `okm_base64` (string, required)
- `length` (integer, required): min 1; max 1024

## Limits

- max ikm bytes: 4096
- max salt bytes: 4096
- max info bytes: 4096
- max length: 1024

## Example

Request input:

```json
{
  "ikm": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
  "ikm_encoding": "hex",
  "salt": "000102030405060708090a0b0c",
  "salt_encoding": "hex",
  "info": "f0f1f2f3f4f5f6f7f8f9",
  "info_encoding": "hex",
  "algorithm": "sha256",
  "length": 42
}
```

Response:

```json
{
  "result": {
    "prk_hex": "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5",
    "okm_hex": "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
    "okm_base64": "PLJfJfqs1XqQQ09k0DYvKi0tCpDPGlpMXbAtVuzExb80AHII1biHGFhl",
    "length": 42
  }
}
```

## How to call it

### MCP

Connect `https://computefirst.net/mcp` ([setup](/docs#connect)), then call `execute` with:

```json
{
  "id": "hkdf-compute",
  "version": "1.0.0",
  "input": {
    "ikm": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
    "ikm_encoding": "hex",
    "salt": "000102030405060708090a0b0c",
    "salt_encoding": "hex",
    "info": "f0f1f2f3f4f5f6f7f8f9",
    "info_encoding": "hex",
    "algorithm": "sha256",
    "length": 42
  }
}
```

### HTTP (no key)

```sh
curl -X POST https://computefirst.net/v1/tools/hkdf-compute/versions/1.0.0/execute \
  -H "Content-Type: application/json" \
  -d '{"ikm":"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b","ikm_encoding":"hex","salt":"000102030405060708090a0b0c","salt_encoding":"hex","info":"f0f1f2f3f4f5f6f7f8f9","info_encoding":"hex","algorithm":"sha256","length":42}'
```

The machine-readable contract is at [/v1/tools/hkdf-compute/versions/1.0.0](/v1/tools/hkdf-compute/versions/1.0.0).

### CLI

```sh
node cli.mjs run hkdf-compute 1.0.0 --input input.json --base-url https://computefirst.net
```

Get the client at [/clients/cli/](/clients/cli/).

## Related tools

- [Pbkdf2 compute](/tools/pbkdf2-compute): Derive a key from a password and salt with PBKDF2-HMAC-SHA1/256/384/512 (RFC 8018), within a hard CPU work-unit budget.
- [Hmac compute](/tools/hmac-compute): Compute HMAC-SHA256/SHA512/MD5/SHA-1/SHA-3/RIPEMD-160 (RFC 2104) over encoded key and message bytes.
- [Crc parametric compute](/tools/crc-parametric-compute): Compute a CRC using a named catalogue preset (CRC-8, CRC-16/ARC, CRC-32/ISO-HDLC, ...) or an explicit Rocksoft model.
- [Hash digest compute](/tools/hash-digest-compute): Compute a message digest (SHA-2, SHA-3, BLAKE2/3, MD5, RIPEMD-160, Keccak-256) over encoded input bytes.
- [Hash noncrypto compute](/tools/hash-noncrypto-compute): Compute FNV-1/1a, MurmurHash3 or xxHash over encoded input bytes, with an optional seed for algorithms that take one.
- [Merkle proof verify](/tools/merkle-proof-verify): Recompute a Merkle root (RFC 9162 or Bitcoin) from one leaf and its audit path, and compare it to a claimed root.
