PBKDF2
Créé en 2000 • PKCS #5 • RFC 2898•Key Derivation
⚠️ STATUT DÉPRÉCIÉ - MIGRATION RECOMMANDÉE
PBKDF2 reste acceptable pour les systèmes legacy mais n'est plus recommandé pour les nouvelles implémentations. Standards gouvernementaux (NIST, ANSSI) exigent 210k+ itérations minimum. Migrez vers Argon2id, bcrypt ou scrypt.
Alternatives Modernes Recommandées 2024
Champion PHC 2015 • Standard moderne
25+ ans éprouvé • Adoption massive
Memory-hard • Résistance ASIC
Pourquoi migrer ? PBKDF2 est CPU-only (vulnérable aux ASICs), consomme peu de mémoire (parallélisation facile), et manque des protections modernes contre les attaques par force brute industrielle.
Implémentations Legacy - Standards Gouvernementaux
Implémentations conformes aux standards NIST SP 800-63B, ANSSI et BSI avec warnings automatiques et recommandations de migration vers alternatives modernes.
Node.js - PBKDF2 Legacy avec Warnings
const crypto = require('crypto');
const { promisify } = require('util');
const pbkdf2 = promisify(crypto.pbkdf2);
// ⚠️ PBKDF2 - Déprécié mais Acceptable pour Legacy 2024
class PBKDF2Manager {
constructor() {
// Configurations selon standards gouvernementaux
this.configs = {
// Configuration minimum (NIST 2024)
minimum: {
iterations: 210000, // NIST SP 800-63B minimum
keylen: 32, // 256-bit output
digest: 'sha256',
saltLength: 32
},
// Configuration gouvernementale (ANSSI, BSI)
government: {
iterations: 600000, // Haute sécurité gouvernementale
keylen: 64, // 512-bit output
digest: 'sha256',
saltLength: 64
},
// Configuration legacy compatible
legacy: {
iterations: 100000, // Ancien minimum acceptable
keylen: 32,
digest: 'sha1', // ⚠️ SHA-1 legacy seulement
saltLength: 16
}
};
// Recommandations alternatives
this.modernAlternatives = [
'Argon2id - Champion PHC 2015-2024',
'bcrypt - Éprouvé depuis 25 ans',
'scrypt - Memory-hard résistant ASIC'
];
}
async hashPassword(password, config = 'government') {
const settings = this.configs[config];
const salt = crypto.randomBytes(settings.saltLength);
const start = process.hrtime.bigint();
try {
const hash = await pbkdf2(
password,
salt,
settings.iterations,
settings.keylen,
settings.digest
);
const duration = Number(process.hrtime.bigint() - start) / 1000000;
// Avertissement automatique si PBKDF2 utilisé
console.warn(`⚠️ PBKDF2 Usage Detected - Consider modern alternatives:
→ Argon2id (recommended 2024)
→ bcrypt (proven reliability)
→ scrypt (ASIC-resistant)`);
return {
hash: hash.toString('base64'),
salt: salt.toString('base64'),
algorithm: 'PBKDF2',
digest: settings.digest,
iterations: settings.iterations,
keyLength: settings.keylen,
config: config,
duration: `${duration.toFixed(0)}ms`,
security_warning: 'Consider modern alternatives',
alternatives: this.modernAlternatives,
compliance: this.getComplianceInfo(config)
};
} catch (error) {
throw new Error(`PBKDF2 failed: ${error.message}`);
}
}
async verifyPassword(password, hash, salt, config = 'government') {
const settings = this.configs[config];
const start = process.hrtime.bigint();
try {
const computedHash = await pbkdf2(
password,
Buffer.from(salt, 'base64'),
settings.iterations,
settings.keylen,
settings.digest
);
const duration = Number(process.hrtime.bigint() - start) / 1000000;
const isValid = crypto.timingSafeEqual(
Buffer.from(hash, 'base64'),
computedHash
);
return {
valid: isValid,
algorithm: 'PBKDF2',
duration: `${duration.toFixed(2)}ms`,
timing_safe: true,
migration_recommendation: isValid ? 'Consider upgrading to Argon2id' : null
};
} catch (error) {
throw new Error(`PBKDF2 verification failed: ${error.message}`);
}
}
// Calcul itérations optimales pour temps cible
async calculateIterationsForTargetTime(targetMs = 500) {
const testPassword = 'benchmark_password';
const testSalt = crypto.randomBytes(32);
let iterations = 100000;
const results = {};
for (let i = 0; i < 3; i++) {
const start = process.hrtime.bigint();
await pbkdf2(testPassword, testSalt, iterations, 32, 'sha256');
const duration = Number(process.hrtime.bigint() - start) / 1000000;
results[iterations] = duration;
if (duration >= targetMs) break;
iterations *= 2;
}
return {
target_time_ms: targetMs,
iterations_tested: results,
recommended_iterations: iterations,
warning: 'PBKDF2 is deprecated - use Argon2id instead',
modern_alternatives: {
'Argon2id': 'Memory-hard, timing ~200-500ms',
'bcrypt': 'Adaptive cost, timing ~100-300ms',
'scrypt': 'Memory-hard, ASIC-resistant'
}
};
}
// Benchmark contre alternatives modernes
benchmarkVsAlternatives() {
return {
pbkdf2: {
security: 'ACCEPTABLE_BUT_DEPRECATED',
performance: 'Good (CPU-bound)',
memory_usage: 'Very low (~1KB)',
asic_resistance: 'Poor',
recommendation: '⚠️ Legacy only - migrate to modern alternatives'
},
argon2id: {
security: 'EXCELLENT_2024_CHAMPION',
performance: 'Configurable (150ms-2s)',
memory_usage: 'Configurable (64MB-1GB)',
asic_resistance: 'Excellent',
recommendation: '✅ Primary choice for new systems'
},
bcrypt: {
security: 'EXCELLENT_PROVEN',
performance: 'Good (100-300ms)',
memory_usage: 'Low (~4KB)',
asic_resistance: 'Good',
recommendation: '✅ Reliable choice for web applications'
},
scrypt: {
security: 'VERY_GOOD',
performance: 'Configurable',
memory_usage: 'High (configurable)',
asic_resistance: 'Excellent',
recommendation: '✅ Good alternative when Argon2 unavailable'
}
};
}
getComplianceInfo(config) {
const compliance = {
minimum: {
nist_sp_800_63b: 'Compliant (210k+ iterations)',
owasp: 'Meets minimum requirements',
pci_dss: 'Acceptable with caveats',
status: 'MINIMUM_COMPLIANCE'
},
government: {
anssi: 'Compliant (600k iterations)',
bsi_tr: 'Meets German standards',
nist_fips: 'FIPS 140-2 compatible',
status: 'HIGH_COMPLIANCE'
},
legacy: {
status: 'DEPRECATED',
warning: 'Below current security standards',
migration_required: true
}
};
return compliance[config];
}
}Python - PBKDF2 Gouvernemental
import hashlib
import secrets
import time
import warnings
from typing import Dict, Any, Optional
class PBKDF2Manager:
"""PBKDF2 Manager avec avertissements et alternatives modernes"""
def __init__(self):
# Émettre warning à l'initialisation
warnings.warn(
"PBKDF2 is deprecated for new applications. "
"Consider Argon2id, bcrypt, or scrypt instead.",
DeprecationWarning,
stacklevel=2
)
# Configurations standards gouvernementaux
self.configs = {
'minimum': {
'iterations': 210000, # NIST SP 800-63B 2024
'key_length': 32, # 256-bit
'hash_algo': 'sha256',
'salt_length': 32
},
'government': {
'iterations': 600000, # ANSSI/BSI high security
'key_length': 64, # 512-bit
'hash_algo': 'sha256',
'salt_length': 64
},
'legacy': {
'iterations': 100000, # Ancien minimum
'key_length': 32,
'hash_algo': 'sha1', # ⚠️ Legacy seulement
'salt_length': 16
}
}
def hash_password(self, password: str, config: str = 'government') -> Dict[str, Any]:
"""Hash mot de passe avec PBKDF2 et avertissement"""
if config not in self.configs:
raise ValueError(f"Unknown config: {config}")
settings = self.configs[config]
salt = secrets.token_bytes(settings['salt_length'])
start_time = time.perf_counter()
# Hash avec PBKDF2
hash_result = hashlib.pbkdf2_hmac(
hash_name=settings['hash_algo'],
password=password.encode('utf-8'),
salt=salt,
iterations=settings['iterations'],
dklen=settings['key_length']
)
duration = time.perf_counter() - start_time
# Warning automatique
print(f"⚠️ PBKDF2 Usage Warning:")
print(f" → Consider upgrading to Argon2id (2024 champion)")
print(f" → Or bcrypt (proven 25+ years reliability)")
print(f" → Current PBKDF2 provides adequate but dated security")
return {
'hash': hash_result.hex(),
'salt': salt.hex(),
'algorithm': 'PBKDF2',
'hash_algo': settings['hash_algo'],
'iterations': settings['iterations'],
'key_length': settings['key_length'],
'config': config,
'duration': f"{duration*1000:.0f}ms",
'security_level': 'DEPRECATED_BUT_ACCEPTABLE',
'migration_recommendation': 'Upgrade to Argon2id when possible',
'compliance': self._get_compliance_info(config)
}
def verify_password(self, password: str, hash_hex: str, salt_hex: str, config: str = 'government') -> Dict[str, Any]:
"""Vérification mot de passe PBKDF2"""
settings = self.configs[config]
start_time = time.perf_counter()
# Reconstituer hash
computed_hash = hashlib.pbkdf2_hmac(
hash_name=settings['hash_algo'],
password=password.encode('utf-8'),
salt=bytes.fromhex(salt_hex),
iterations=settings['iterations'],
dklen=settings['key_length']
)
duration = time.perf_counter() - start_time
# Comparaison timing-safe
is_valid = secrets.compare_digest(hash_hex, computed_hash.hex())
return {
'valid': is_valid,
'algorithm': 'PBKDF2',
'duration': f"{duration*1000:.2f}ms",
'timing_safe': True,
'upgrade_recommendation': 'Consider migrating to Argon2id' if is_valid else None
}
def calculate_iterations_for_target_time(self, target_ms: int = 500) -> Dict[str, Any]:
"""Calcul itérations optimales pour temps cible"""
test_password = 'benchmark_test_password'
test_salt = secrets.token_bytes(32)
iterations = 100000
results = {}
for _ in range(5):
start_time = time.perf_counter()
hashlib.pbkdf2_hmac('sha256', test_password.encode(), test_salt, iterations, 32)
duration_ms = (time.perf_counter() - start_time) * 1000
results[iterations] = round(duration_ms)
if duration_ms >= target_ms:
break
iterations = int(iterations * 1.5)
return {
'target_time_ms': target_ms,
'benchmark_results': results,
'recommended_iterations': iterations,
'warning': '⚠️ PBKDF2 deprecated - use Argon2id instead',
'better_alternatives': {
'Argon2id': 'Memory-hard, PHC winner, configurable',
'bcrypt': 'Adaptive cost, battle-tested 25+ years',
'scrypt': 'Memory-hard, ASIC-resistant'
}
}
def benchmark_vs_alternatives(self) -> Dict[str, Any]:
"""Benchmark PBKDF2 vs alternatives modernes"""
return {
'pbkdf2': {
'year': '2000 (PKCS #5)',
'status': 'DEPRECATED_BUT_ACCEPTABLE',
'security_2024': 'Adequate with 210k+ iterations',
'performance': 'Good (CPU-only)',
'memory_usage': 'Very low (~1KB)',
'asic_resistance': 'Poor',
'adoption': 'Legacy systems',
'recommendation': '⚠️ Migrate to modern alternatives'
},
'argon2id': {
'year': '2015 (PHC Winner)',
'status': 'MODERN_CHAMPION',
'security_2024': 'Excellent - state of the art',
'performance': 'Configurable (150ms-2s)',
'memory_usage': 'Configurable (64MB-1GB+)',
'asic_resistance': 'Excellent',
'adoption': 'New systems, security-critical',
'recommendation': '✅ Primary choice 2024'
},
'bcrypt': {
'year': '1999',
'status': 'PROVEN_RELIABLE',
'security_2024': 'Excellent - proven track record',
'performance': 'Good (100-300ms)',
'memory_usage': 'Low (~4KB)',
'asic_resistance': 'Good',
'adoption': 'Massive (web applications)',
'recommendation': '✅ Reliable alternative'
}
}
def _get_compliance_info(self, config: str) -> Dict[str, Any]:
"""Information conformité standards"""
compliance_map = {
'minimum': {
'nist_sp_800_63b': '✅ Compliant (210k iterations)',
'owasp': '✅ Meets 2024 requirements',
'pci_dss': '⚠️ Acceptable but not recommended',
'level': 'MINIMUM_ACCEPTABLE'
},
'government': {
'anssi': '✅ Compliant (600k iterations)',
'bsi_tr_02102': '✅ German government standard',
'nist_fips_140_2': '✅ Compatible',
'level': 'HIGH_SECURITY_COMPLIANT'
},
'legacy': {
'status': '❌ BELOW_CURRENT_STANDARDS',
'warning': 'Immediate upgrade required',
'level': 'NON_COMPLIANT_2024'
}
}
return compliance_map.get(config, {'level': 'UNKNOWN'})
# Usage avec avertissements appropriés
if __name__ == "__main__":
# Warning global
print("⚠️ PBKDF2 USAGE DETECTED - MODERN ALTERNATIVES RECOMMENDED")
print("=" * 65)
print("✅ Argon2id: Memory-hard, PHC winner 2015")
print("✅ bcrypt: 25+ years proven, adaptive cost")
print("✅ scrypt: Memory-hard, ASIC-resistant")
print("⚠️ PBKDF2: Acceptable for legacy, not recommended for new systems")
print("=" * 65)
manager = PBKDF2Manager()
# Test avec configuration gouvernementale
password = "MotDePasseComplexe2024!"
hash_result = manager.hash_password(password, 'government')
print(f"\nPBKDF2 Result: {hash_result}\n")
# Vérification
verify_result = manager.verify_password(
password,
hash_result['hash'],
hash_result['salt'],
'government'
)
print(f"Verification: {verify_result}\n")
# Benchmark alternatives
comparison = manager.benchmark_vs_alternatives()
print("Modern Alternatives Comparison:")
for alg, info in comparison.items():
print(f"{alg}: {info['recommendation']}"))📋 Standards de Conformité 2024
- • NIST SP 800-63B: 210k+ itérations
- • ANSSI: 600k itérations recommandées
- • BSI TR-02102: Conformité allemande
- • PCI DSS: Acceptable avec caveats
- • CPU-only (vulnérable ASICs)
- • Faible usage mémoire (~1KB)
- • Parallélisation facile
- • Pas de résistance GPU moderne
⚠️ Statut PBKDF2
Alternatives Modernes
PBKDF2 reste acceptable pour legacy mais migrez vers Argon2id pour la sécurité moderne.
Guide de Migration PBKDF2 → Alternatives Modernes
• Systèmes existants: Migration graduelle
• Rehash progressif à la connexion
• Compatibilité: Excellente universalité
• Migration: Simple, éprouvée
• Monitoring: Temps de calcul
• Planning: Migration 2024-2025
PBKDF2 : L'Héritage à Moderniser
PBKDF2 a servi fidèlement pendant 25 ans mais les menaces modernes (ASICs, GPUs, cloud computing) dépassent ses capacités défensives. Standards gouvernementaux maintiennent la compatibilité legacy, mais toute nouvelle implémentation doit privilégier Argon2id ou bcrypt.