HMAC-DRBG Security-Focused API Documentation
Algorithm: HMAC-DRBG (Deterministic Random Bit Generator)
Type: Pseudorandom Number Generator
Security Level: Based on underlying hash (SHA-256: 128-bit)
Specification: NIST SP 800-90A Rev. 1
Security Contract
hmacDrbg.create(entropy: Uint8Array, personalization?: Uint8Array): HmacDrbg
Preconditions:
- Entropy: Minimum security_strength bits (32 bytes for SHA-256)
- Personalization: Optional, any length
- Hash function: SHA-256 or SHA-512
Postconditions:
- Returns initialized DRBG instance
- Ready to generate up to 2^48 requests
- Backtracking resistance enabled
Side Effects:
- Maintains internal state
- No external randomness after init
drbg.generate(length: number): Uint8Array
Preconditions:
- Length: 1 to 2^19 bits (64KB)
- Not more than 2^48 requests
- Instance not compromised
Postconditions:
- Returns
lengthpseudorandom bytes - Updates internal state
- Forward security maintained
Side Effects:
- Internal state updated
- Reseed counter incremented
Attack Resistance Matrix
| Attack Type | Resistance | Notes |
|---|---|---|
| State Compromise | ✅ Forward Secure | Past outputs safe |
| Backtracking | ✅ Strong | Can’t compute previous |
| Prediction | ✅ Strong | Without state |
| Side-Channel | ✅ Good | HMAC is robust |
| Reseed Failure | ⚠️ Degrades | Need fresh entropy |
| State Cloning | ❌ Vulnerable | Must prevent |
| Quantum | ⚠️ Reduced | Hash security halved |
Secure Usage Examples
✅ CORRECT: Nonce Generation
import { hmacDrbg } from 'metamui-hmac-drbg';
class NonceGenerator {
private drbg: HmacDrbg;
constructor(masterSeed: Uint8Array) {
// Initialize with personalization
this.drbg = hmacDrbg.create(
masterSeed,
stringToBytes("MyApp-Nonce-v1")
);
}
// Generate unique nonces
generateNonce(length: number = 16): Uint8Array {
return this.drbg.generate(length);
}
// Reseed periodically
reseed(additionalEntropy: Uint8Array): void {
this.drbg.reseed(additionalEntropy);
}
}
// Usage
const nonceGen = new NonceGenerator(deviceSecret);
const nonce1 = nonceGen.generateNonce(); // Unique
const nonce2 = nonceGen.generateNonce(); // Different
✅ CORRECT: Deterministic Key Derivation
import { hmacDrbg } from 'metamui-hmac-drbg';
// HD wallet key generation
class DeterministicKeyGen {
private drbg: HmacDrbg;
constructor(seed: Uint8Array, purpose: string) {
this.drbg = hmacDrbg.create(
seed,
stringToBytes(`HDWallet-${purpose}`)
);
}
deriveKey(index: number): Uint8Array {
// Add index to additional input
const additionalInput = new Uint8Array(4);
new DataView(additionalInput.buffer).setUint32(0, index, false);
return this.drbg.generateWithAdditional(
32, // 256-bit key
additionalInput
);
}
// Derive multiple keys efficiently
deriveKeys(count: number): Uint8Array[] {
const keys: Uint8Array[] = [];
for (let i = 0; i < count; i++) {
keys.push(this.deriveKey(i));
}
return keys;
}
}
✅ CORRECT: Session Key Rotation
import { hmacDrbg } from 'metamui-hmac-drbg';
class ForwardSecureSession {
private drbg: HmacDrbg;
private epoch: number = 0;
constructor(sharedSecret: Uint8Array) {
this.drbg = hmacDrbg.create(
sharedSecret,
stringToBytes("ForwardSecure-v1")
);
}
// Get current epoch key
getCurrentKey(): Uint8Array {
return this.drbg.generateWithAdditional(
32,
encodeUint32(this.epoch)
);
}
// Advance to next epoch (one-way)
advance(): void {
this.epoch++;
// Optional: Reseed for extra security
if (this.epoch % 1000 === 0) {
const epochSeed = this.drbg.generate(32);
this.drbg.reseed(epochSeed);
}
}
// Cannot go backward (forward secure)
getKeyForEpoch(epoch: number): Uint8Array | null {
if (epoch < this.epoch) {
return null; // Can't compute past keys
}
// Advance to requested epoch
while (this.epoch < epoch) {
this.advance();
}
return this.getCurrentKey();
}
}
✅ CORRECT: Test Vector Generation
import { hmacDrbg } from 'metamui-hmac-drbg';
// Reproducible test vectors
function generateTestVectors(
algorithm: string,
count: number
): TestVector[] {
// Fixed seed for reproducibility
const seed = hexToBytes(
"0123456789abcdef0123456789abcdef" +
"0123456789abcdef0123456789abcdef"
);
const drbg = hmacDrbg.create(
seed,
stringToBytes(`TestVectors-${algorithm}`)
);
const vectors: TestVector[] = [];
for (let i = 0; i < count; i++) {
const input = drbg.generate(32);
const key = drbg.generate(32);
vectors.push({
input: bytesToHex(input),
key: bytesToHex(key),
algorithm
});
}
return vectors;
}
Common Mistakes to Avoid
❌ WRONG: Weak Entropy
// NEVER DO THIS - Predictable seed
const timestamp = Date.now();
const weakSeed = new Uint8Array(8);
new DataView(weakSeed.buffer).setBigUint64(0, BigInt(timestamp));
const drbg = hmacDrbg.create(weakSeed); // Only 64 bits!
// ✅ CORRECT: Use proper entropy
const strongSeed = crypto.getRandomValues(new Uint8Array(32));
const drbg = hmacDrbg.create(strongSeed); // 256 bits
❌ WRONG: State Cloning
// NEVER DO THIS - Cloning DRBG state
const drbg1 = hmacDrbg.create(seed);
const state = drbg1.exportState(); // If this existed
const drbg2 = hmacDrbg.importState(state); // Both generate same!
// ✅ CORRECT: Derive independent instances
const master = hmacDrbg.create(seed);
const seed1 = master.generate(32);
const seed2 = master.generate(32);
const drbg1 = hmacDrbg.create(seed1); // Independent
const drbg2 = hmacDrbg.create(seed2); // Different output
❌ WRONG: No Reseeding
// NEVER DO THIS - Never reseeding
const drbg = hmacDrbg.create(initialSeed);
// Generate millions of bytes without reseeding
for (let i = 0; i < 1000000; i++) {
const data = drbg.generate(1024); // No fresh entropy
}
// ✅ CORRECT: Periodic reseeding
const drbg = hmacDrbg.create(initialSeed);
let generated = 0;
for (let i = 0; i < 1000000; i++) {
const data = drbg.generate(1024);
generated += 1024;
// Reseed every 1MB
if (generated >= 1024 * 1024) {
const freshEntropy = crypto.getRandomValues(new Uint8Array(32));
drbg.reseed(freshEntropy);
generated = 0;
}
}
Implementation Security
HMAC-DRBG Internals
class HmacDrbgImplementation {
private V: Uint8Array; // Internal state V
private K: Uint8Array; // HMAC key
private reseedCounter: number;
constructor(
entropy: Uint8Array,
personalization?: Uint8Array,
nonce?: Uint8Array
) {
// Initialize V and K
this.V = new Uint8Array(32).fill(0x01);
this.K = new Uint8Array(32).fill(0x00);
// Instantiate with entropy
const seedMaterial = concat(
entropy,
nonce || new Uint8Array(0),
personalization || new Uint8Array(0)
);
this.update(seedMaterial);
this.reseedCounter = 1;
}
private update(providedData?: Uint8Array): void {
// K = HMAC(K, V || 0x00 || provided_data)
const input = concat(
this.V,
new Uint8Array([0x00]),
providedData || new Uint8Array(0)
);
this.K = hmac(this.K, input);
// V = HMAC(K, V)
this.V = hmac(this.K, this.V);
if (providedData && providedData.length > 0) {
// K = HMAC(K, V || 0x01 || provided_data)
const input2 = concat(
this.V,
new Uint8Array([0x01]),
providedData
);
this.K = hmac(this.K, input2);
this.V = hmac(this.K, this.V);
}
}
generate(length: number, additionalInput?: Uint8Array): Uint8Array {
if (this.reseedCounter > RESEED_INTERVAL) {
throw new Error("Reseed required");
}
if (additionalInput) {
this.update(additionalInput);
}
// Generate output
const output = new Uint8Array(length);
let offset = 0;
while (offset < length) {
this.V = hmac(this.K, this.V);
const copyLength = Math.min(32, length - offset);
output.set(this.V.slice(0, copyLength), offset);
offset += copyLength;
}
this.update(additionalInput);
this.reseedCounter++;
return output;
}
}
Platform-Specific Notes
Performance
- Generation: ~1-2 MB/s (SHA-256)
- Overhead: ~100 bytes per request
- Memory: 64 bytes state + stack
Comparison with Other DRBGs
| Feature | HMAC-DRBG | CTR-DRBG | Hash-DRBG |
|---|---|---|---|
| Speed | Moderate | Fast | Slow |
| Security Proof | Strong | Strong | Moderate |
| Side-Channel | Good | Needs AES-NI | Good |
| Simplicity | Simple | Complex | Simple |
When to Use HMAC-DRBG
✅ Appropriate Uses:
- Nonce generation
- Deterministic key derivation
- Test vector generation
- Session key rotation
- Reproducible randomness
- Forward-secure protocols
❌ Inappropriate Uses:
- Long-term key generation (use OS RNG)
- High-volume random data (use CTR-DRBG)
- Cryptographic keys (use proper KDF)
- When true randomness required
Security Checklist
- Use minimum 256-bit entropy for initialization
- Include personalization string
- Never clone or serialize state
- Reseed periodically with fresh entropy
- Clear state when done
- Use additional input for domain separation
- Monitor reseed counter
- Protect against VM rollback attacks
Security Analysis
Threat Model: HMAC-DRBG Threat Model
The comprehensive threat analysis covers:
- Algorithm-specific attack vectors
- Implementation vulnerabilities
- Side-channel considerations
- Quantum resistance analysis (where applicable)
- Deployment recommendations
For complete security analysis and risk assessment, see the dedicated threat model documentation.