Unified KDF Interface Documentation
Side-channel claim limit. Nothing on this page claims constant-time behaviour or side-channel resistance for any target: the side-channel harness covers nothing (finding A48) and no measurement exists. The Rust and C cores are designed for constant time and unmeasured; managed runtimes (JIT, GC, bounds checks) make no timing claim. Where this page names constant-time or side-channel techniques, in prose or in code, they are design intent or recommendations, not measured properties.
This document defines the unified interface for Key Derivation Functions (KDFs) across all MetaMUI implementations.
Common Interface Pattern
All KDF implementations follow a consistent pattern across languages:
Class/Module Structure
KDF
├── Static Methods (Primary Interface)
│ ├── derive() or hash()
│ ├── verify() (for password hashing)
│ └── Convenience methods
├── Configuration
│ └── Parameters with sensible defaults
└── Error Handling
└── Consistent error types
PBKDF2 Interface
Rust
use metamui_pbkdf2::PBKDF2;
// Primary methods
PBKDF2::pbkdf2_hmac_sha256(password: &[u8], salt: &[u8], iterations: u32, key_length: usize) -> Result<Vec<u8>, PBKDF2Error>
PBKDF2::pbkdf2_hmac_sha512(password: &[u8], salt: &[u8], iterations: u32, key_length: usize) -> Result<Vec<u8>, PBKDF2Error>
// BIP39 convenience
PBKDF2::bip39_mnemonic_to_seed(mnemonic: &str, passphrase: &str) -> Vec<u8>
Python
from metamui_crypto.pbkdf2 import PBKDF2
# Primary methods
PBKDF2.derive_key_sha256(password: Union[str, bytes], salt: Union[str, bytes], iterations: int, key_length: int) -> bytes
PBKDF2.derive_key_sha512(password: Union[str, bytes], salt: Union[str, bytes], iterations: int, key_length: int) -> bytes
# BIP39 convenience
PBKDF2.bip39_mnemonic_to_seed(mnemonic: str, passphrase: str = "") -> bytes
TypeScript
import { PBKDF2 } from '@metamui/crypto-pbkdf2';
// Primary methods
PBKDF2.sha256(password: Uint8Array, salt: Uint8Array, iterations: number, keyLength: number): Uint8Array
PBKDF2.sha512(password: Uint8Array, salt: Uint8Array, iterations: number, keyLength: number): Uint8Array
// Generic method
PBKDF2.derive(password: Uint8Array, salt: Uint8Array, iterations: number, keyLength: number, algorithm: 'sha256' | 'sha512'): Uint8Array
Swift
import MetaMUIPBKDF2
// Primary methods
PBKDF2.deriveKey(password: Data, salt: Data, iterations: UInt32, keyLength: Int, variant: .sha256) throws -> Data
PBKDF2.deriveKey(password: Data, salt: Data, iterations: UInt32, keyLength: Int, variant: .sha512) throws -> Data
// BIP39 convenience
PBKDF2.bip39MnemonicToSeed(mnemonic: String, passphrase: String = "") -> Data
Kotlin
import id.metamui.crypto.pbkdf2.PBKDF2
// Primary methods
PBKDF2.deriveKeySha256(password: ByteArray, salt: ByteArray, iterations: Int, keyLength: Int): ByteArray
PBKDF2.deriveKeySha512(password: ByteArray, salt: ByteArray, iterations: Int, keyLength: Int): ByteArray
// BIP39 convenience
PBKDF2.bip39MnemonicToSeed(mnemonic: String, passphrase: String = ""): ByteArray
Argon2 Interface
Rust
use metamui_argon2::{MetaMUIArgon2, Argon2Config, Argon2Variant};
// Create hasher with config
let config = Argon2Config {
variant: Argon2Variant::Argon2id,
memory_cost: 19456,
time_cost: 2,
parallelism: 1,
output_length: 32,
..Default::default()
};
let argon2 = MetaMUIArgon2::with_config(config)?;
// Hash password
let hash = argon2.hash_password(password)?;
// Verify password
let valid = argon2.verify_password(password, &hash);
// Derive key
let key = argon2.derive_key(password, salt, output_length)?;
Python
from metamui_crypto.argon2 import Argon2, Argon2Type
argon2 = Argon2()
# Hash with parameters
hash_output = argon2.hash(
password="password",
salt=b"somesalt12345678",
time_cost=2,
memory_cost=19456,
parallelism=1,
tag_length=32,
argon2_type=Argon2Type.ARGON2ID
)
# Verify
valid = argon2.verify(password, salt, hash_to_verify, **same_params)
TypeScript
import { Argon2, Argon2Type } from '@metamui/crypto-argon2';
const argon2 = new Argon2();
// Hash with parameters
const hash = argon2.hash(password, salt, {
type: Argon2Type.Argon2id,
timeCost: 2,
memoryCost: 19456,
parallelism: 1,
tagLength: 32
});
// Verify
const valid = argon2.verify(password, salt, hash, params);
Swift
import MetaMUIArgon2
// Hash with parameters
let hash = try Argon2.hash(
password: password,
salt: salt,
type: .argon2id,
iterations: 2,
memory: 19456,
parallelism: 1,
tagLength: 32
)
// Verify
let valid = Argon2.verify(password: password, hash: hash)
Kotlin
import id.metamui.crypto.argon2.Argon2
// Hash with parameters
val hash = Argon2.hash(
password = password,
salt = salt,
variant = Argon2.Variant.ARGON2ID,
memoryCost = 19456,
timeCost = 2,
parallelism = 1,
outputLength = 32
)
// Verify
val valid = Argon2.verify(password, hash)
HKDF Interface
Rust
use metamui_hkdf::{MetaMUIHkdfSha256, MetaMUIHkdfSha512};
// Extract-and-Expand
let result = MetaMUIHkdfSha256::derive(ikm, salt, info, output_length)?;
// Separate Extract/Expand
let prk = MetaMUIHkdfSha256::extract(ikm, salt);
let okm = MetaMUIHkdfSha256::expand(&prk, info, output_length)?;
Python
from metamui_crypto.hkdf import MetaMUIHkdf
hkdf = MetaMUIHkdf()
# SHA-256
output = hkdf.hkdf_sha256(ikm, salt, info, output_length)
# SHA-512
output = hkdf.hkdf_sha512(ikm, salt, info, output_length)
# Extract only
prk = hkdf.extract_sha256(salt, ikm)
TypeScript
import { HKDF } from '@metamui/crypto-utilities';
const hkdf = new HKDF();
// SHA-256
const output = hkdf.hkdfSha256(ikm, salt, info, outputLength);
// SHA-512
const output = hkdf.hkdfSha512(ikm, salt, info, outputLength);
Swift
import MetaMUIHkdf
// SHA-256
let output = try Hkdf.deriveKey(
ikm: ikm,
salt: salt,
info: info,
outputLength: outputLength,
variant: .sha256
)
Kotlin
import id.metamui.crypto.hkdf.HKDF
// SHA-256
val output = HKDF.deriveKeySha256(ikm, salt, info, outputLength)
// SHA-512
val output = HKDF.deriveKeySha512(ikm, salt, info, outputLength)
Error Handling
Common Error Types
All implementations provide these error types:
- InvalidParameters - Invalid input parameters (iterations, length, etc.)
- InvalidKey - Key-related errors
- DerivationFailed - KDF operation failed
- VerificationFailed - Password verification failed (Argon2)
Error Handling Examples
Rust
match PBKDF2::pbkdf2_hmac_sha256(password, salt, 0, 32) {
Ok(key) => // use key,
Err(PBKDF2Error::InvalidIterations) => // handle error,
Err(e) => // handle other errors
}
Python
try:
key = PBKDF2.derive_key_sha256(password, salt, 0, 32)
except InvalidIterationsError as e:
# handle invalid iterations
except PBKDF2Error as e:
# handle other errors
TypeScript
try {
const key = PBKDF2.sha256(password, salt, 0, 32);
} catch (e) {
if (e instanceof InvalidIterationsError) {
// handle invalid iterations
}
}
Best Practices
- Input Validation
- Always validate parameters before processing
- Enforce minimum security requirements
- Provide clear error messages
- Memory Security
- Clear sensitive data after use
- Use secure memory allocation where available
- Implement constant-time operations for password verification
- Default Parameters
- Provide secure defaults
- Allow customization for specific use cases
- Document recommended values
- Type Safety
- Use strong typing where available
- Accept both string and byte inputs where appropriate
- Return consistent types across methods
- Performance
- Implement HMAC key caching for PBKDF2
- Use optimized hash implementations
- Consider parallelism for Argon2
Migration Guide
From External Libraries
Rust (from pbkdf2 crate)
// Before
use pbkdf2::pbkdf2_hmac;
pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut output);
// After
use metamui_pbkdf2::PBKDF2;
let output = PBKDF2::pbkdf2_hmac_sha256(password, salt, iterations, length)?;
Python (from hashlib.pbkdf2_hmac)
# Before
import hashlib
key = hashlib.pbkdf2_hmac('sha256', password, salt, iterations)
# After
from metamui_crypto.pbkdf2 import PBKDF2
key = PBKDF2.derive_key_sha256(password, salt, iterations, 32)
TypeScript (from crypto.pbkdf2)
// Before
import { pbkdf2Sync } from 'crypto';
const key = pbkdf2Sync(password, salt, iterations, keylen, 'sha256');
// After
import { PBKDF2 } from '@metamui/crypto-pbkdf2';
const key = PBKDF2.sha256(password, salt, iterations, keylen);
Testing
All implementations should include:
- Unit Tests
- Test vectors from RFCs
- Edge cases (empty inputs, maximum lengths)
- Error conditions
- Cross-Language Tests
- Shared test vectors
- Compatibility verification
- Performance benchmarks
- Security Tests
- Timing attack resistance
- Memory clearing verification
- Parameter validation