Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Kdf unstable

Key derivation: HKDF, PBKDF2, and Argon2id.

The Kdf service derives bytes from a secret with an algorithm value such as hkdfSha256, pbkdf2Sha256, or argon2id(). The output is plain bytes: turn it into a typed key with the target family's raw constructor, such as Mac.key.

Gotchas

  • The secret is bytes, with no string overload. Encode passwords yourself, and normalize their Unicode form first if users type them on different platforms.
  • layerWebCrypto does not provide Argon2id, because WebCrypto has no Argon2. Deriving with it fails with an Unsupported reason, so programs can fall back to PBKDF2. NodeCrypto.layerKdf provides Argon2id on Node.js 24.7 or later and Bun 1.4.
14 exports Since v4.0.0 Source

Algorithms

argon2id

unstable
Since v4.0.0

Builds an Argon2id algorithm, with memory in KiB.

Details

Omitted costs default to RFC 9106's second recommended setting: 64 MiB of memory (65_536), 3 passes, and 4 lanes.

Gotchas

Kdf.layerWebCrypto does not provide Argon2id. Use NodeCrypto.layerKdf, or fall back to PBKDF2 on the Unsupported reason.

Signature

declare function argon2id(options?: {
readonly memory?: number;
readonly parallelism?: number;
readonly passes?: number;
}): Argon2id

hkdf

unstable
Since v4.0.0

Builds the HKDF algorithm for a hash.

Signature

declare function hkdf(hash: Algorithm): Hkdf

hkdfSha1

unstable
Since v4.0.0

HKDF with SHA-1.

Signature

declare const hkdfSha1: Hkdf

hkdfSha256

unstable
Since v4.0.0

HKDF with SHA-256.

Signature

declare const hkdfSha256: Hkdf

hkdfSha384

unstable
Since v4.0.0

HKDF with SHA-384.

Signature

declare const hkdfSha384: Hkdf

hkdfSha512

unstable
Since v4.0.0

HKDF with SHA-512.

Signature

declare const hkdfSha512: Hkdf

pbkdf2

unstable
Since v4.0.0

Builds a PBKDF2 algorithm for a hash and an iteration count.

Details

Deriving with an iteration count outside 1 to 2^31 - 1 fails with an InvalidArgument reason.

Signature

declare function pbkdf2(options: {
readonly hash: Algorithm;
readonly iterations: number;
}): Pbkdf2
Since v4.0.0

PBKDF2 with SHA-256 at 600,000 iterations, OWASP's current figure.

Signature

declare const pbkdf2Sha256: Pbkdf2

Layers

Since v4.0.0

Layer that provides Kdf on the WebCrypto reference.

Details

HKDF and PBKDF2 run on crypto.subtle, off the event loop where the runtime supports it. Argon2id fails with an Unsupported reason.

Signature

declare const layerWebCrypto: Layer.Layer<Kdf>

Models

Algorithm

type unstable
Since v4.0.0

A key derivation algorithm.

Signature

type Algorithm = Hkdf | Pbkdf2 | Argon2id

Argon2id

interface unstable
Since v4.0.0

Argon2id (RFC 9106) with its cost parameters, from argon2id.

Details

memory is in KiB, passes is the number of passes over the memory, and parallelism is the number of lanes.

Signature

interface Argon2id {
readonly _tag: "Argon2id";
readonly memory: number;
readonly name: string;
readonly parallelism: number;
readonly passes: number;
}

Hkdf

interface unstable
Since v4.0.0

HKDF (RFC 5869) with a hash, from hkdf.

Signature

interface Hkdf {
readonly _tag: "Hkdf";
readonly hash: Algorithm;
readonly name: string;
}

Pbkdf2

interface unstable
Since v4.0.0

PBKDF2 (RFC 8018) with a hash and an iteration count, from pbkdf2.

Signature

interface Pbkdf2 {
readonly _tag: "Pbkdf2";
readonly hash: Algorithm;
readonly iterations: number;
readonly name: string;
}

Services

Kdf

unstable
Since v4.0.0

Service that derives bytes from a secret.

Signature

declare class Kdf extends Shape<"effect/crypto/Kdf", {
readonly derive: (algorithm: Algorithm, secret: Uint8Array, options: {
readonly info?: Uint8Array<ArrayBufferLike>;
readonly length: number;
readonly salt: Uint8Array;
}) => Effect<Uint8Array<ArrayBufferLike>, CryptoError>;
}, this> {
constructor(_: never);
}

Example Deriving a key with HKDF

import { Effect } from "effect"
import { Kdf } from "effect/crypto"
const program = Effect.gen(function*() {
const kdf = yield* Kdf.Kdf
return yield* kdf.derive(Kdf.hkdfSha256, new Uint8Array(32), {
salt: new Uint8Array(16),
info: new TextEncoder().encode("encryption"),
length: 32
})
})
const bytes = await Effect.runPromise(program.pipe(Effect.provide(Kdf.layerWebCrypto)))
bytes.length // => 32