FIPS Compliance Skill¶
Tu es expert cryptographie FIPS, orienté conformité NIST et validation FIPS 140-2/140-3.
Mission¶
Garantir la conformité FIPS des opérations cryptographiques de ProbatioVault selon les standards NIST.
Standards FIPS applicables¶
| Standard | Description | Application ProbatioVault |
|---|---|---|
| FIPS 140-2/140-3 | Security Requirements for Cryptographic Modules | CloudHSM (Level 3) |
| FIPS 180-4 | Secure Hash Standard (SHA-2) | ❌ Obsolète pour ProbatioVault |
| FIPS 202 | SHA-3 Standard (Keccak) | ✅ Hash probatoires |
| FIPS 186-4 | Digital Signature Standard | RSA, ECDSA |
| FIPS 197 | Advanced Encryption Standard (AES) | AES-256 |
1. FIPS 140-2/140-3 - Cryptographic Modules¶
Niveaux de sécurité¶
| Level | Description | ProbatioVault Usage |
|---|---|---|
| Level 1 | Software crypto | ❌ Insuffisant pour clés critiques |
| Level 2 | Tamper-evident hardware | ⚠️ Acceptable pour certaines opérations |
| Level 3 | Tamper-resistant hardware | ✅ CloudHSM pour clés maîtres |
| Level 4 | Tamper-responsive hardware | N/A (overkill) |
CloudHSM FIPS 140-2 Level 3¶
// ✅ CONFORME - Opérations dans CloudHSM Level 3
class HSMCryptoService {
constructor(private cloudhsm: CloudHSMClient) {}
async generateMasterKey(orgId: string): Promise<KeyHandle> {
// Génération dans le HSM (FIPS 140-2 Level 3)
const keyHandle = await this.cloudhsm.generateKey({
KeyType: 'AES',
KeySize: 256,
Label: `K_master_org_${orgId}`,
Extractable: false, // Clé NON extractable du HSM
KeyUsage: ['ENCRYPT', 'DECRYPT', 'SIGN', 'VERIFY'],
});
return keyHandle;
}
async signInHSM(data: Buffer, keyHandle: KeyHandle): Promise<Buffer> {
// Signature dans le HSM (clé privée ne quitte jamais le HSM)
const signature = await this.cloudhsm.sign({
KeyHandle: keyHandle,
Data: data,
SigningAlgorithm: 'RSA_PKCS_PSS_SHA3_256',
});
return signature;
}
}
// ❌ INTERDIT - Clés critiques hors HSM
class InsecureCrypto {
async generateMasterKey(): Promise<Buffer> {
// Clé générée en software (FIPS Level 1)
return randomBytes(32); // NON CONFORME pour clés critiques
}
}
Certification FIPS 140-2¶
Vérification : https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules
// ✅ CONFORME - Vérification certification CloudHSM
const AWS_CLOUDHSM_CERTIFICATION = {
module_name: 'AWS CloudHSM',
certificate_number: '3254', // Exemple, vérifier numéro actuel
validation_date: '2019-06-28',
fips_level: 'Level 3',
security_level: {
cryptographic_module_specification: 3,
cryptographic_module_ports_and_interfaces: 3,
roles_services_authentication: 3,
finite_state_model: 3,
physical_security: 3,
operational_environment: 'N/A',
cryptographic_key_management: 3,
electromagnetic_interference: 3,
self_tests: 3,
design_assurance: 3,
mitigation_of_other_attacks: 'N/A',
},
};
2. FIPS 202 - SHA-3 Standard¶
SHA3-256 obligatoire¶
Algorithme : Keccak (SHA-3 family)
import { sha3_256 } from '@noble/hashes/sha3';
import { bytesToHex } from '@noble/hashes/utils';
// ✅ CONFORME FIPS 202
function hashDocument(content: Buffer): string {
const hash = sha3_256(content);
return bytesToHex(hash);
}
// ❌ NON CONFORME (SHA-256 est FIPS 180-4, pas FIPS 202)
import { createHash } from 'crypto';
function hashDocument(content: Buffer): string {
return createHash('sha256').update(content).digest('hex');
}
Test Vectors FIPS 202¶
Obligation : Valider avec test vectors officiels NIST.
// ✅ CONFORME - Test vectors FIPS 202
describe('FIPS 202 SHA3-256 Test Vectors', () => {
const TEST_VECTORS = [
{
// NIST CAVP SHA3-256 ShortMsg Test Case 0
input: '',
expected: 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a',
},
{
// Test Case 1
input: 'abc',
expected: '3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532',
},
{
// Test Case 2
input: 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
expected: '41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376',
},
];
TEST_VECTORS.forEach(({ input, expected }) => {
it(`should hash "${input}" correctly (FIPS 202)`, () => {
const result = bytesToHex(sha3_256(Buffer.from(input)));
expect(result).toBe(expected);
});
});
});
SHA-3 vs SHA-2¶
| Aspect | SHA-2 (FIPS 180-4) | SHA-3 (FIPS 202) |
|---|---|---|
| Famille | Merkle-Damgård | Keccak (sponge) |
| Résistance collisions | Prouvée | Prouvée |
| Valeur probatoire | ✅ Acceptable | ✅ Recommandé |
| ProbatioVault | ❌ Non utilisé | ✅ Standard |
Raison choix SHA-3 : Plus récent, architecture différente (redondance sécurité), recommandé ANSSI pour applications probatoires.
3. FIPS 197 - Advanced Encryption Standard (AES)¶
AES-256-GCM obligatoire¶
Algorithme : AES-256 en mode GCM (Galois/Counter Mode)
Référence : NIST SP 800-38D
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
// ✅ CONFORME FIPS 197 + NIST SP 800-38D
class AESGCMCipher {
async encrypt(plaintext: Buffer, key: Buffer): Promise<EncryptionResult> {
// Vérifications FIPS
if (key.length !== 32) {
throw new Error('FIPS 197: Key must be 256 bits (32 bytes)');
}
// IV 96 bits pour GCM (recommandation NIST SP 800-38D)
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', key, iv);
const ciphertext = Buffer.concat([
cipher.update(plaintext),
cipher.final(),
]);
// Tag d'authentification 128 bits (obligatoire GCM)
const tag = cipher.getAuthTag();
return { ciphertext, iv, tag };
}
async decrypt(
ciphertext: Buffer,
key: Buffer,
iv: Buffer,
tag: Buffer
): Promise<Buffer> {
const decipher = createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
const plaintext = Buffer.concat([
decipher.update(ciphertext),
decipher.final(), // Lève exception si tag invalide
]);
return plaintext;
}
}
// ❌ NON CONFORME - AES-CBC sans HMAC
const cipher = createCipheriv('aes-256-cbc', key, iv); // Pas d'authentification
Test Vectors AES-GCM¶
// ✅ CONFORME - Test vectors NIST SP 800-38D Appendix B
describe('NIST SP 800-38D AES-256-GCM Test Vectors', () => {
it('should encrypt correctly (Test Case 13)', async () => {
const key = Buffer.from(
'00000000000000000000000000000000' +
'00000000000000000000000000000000',
'hex'
);
const iv = Buffer.from('000000000000000000000000', 'hex');
const plaintext = Buffer.from('');
const aad = Buffer.from('');
const cipher = createCipheriv('aes-256-gcm', key, iv);
cipher.setAAD(aad);
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = cipher.getAuthTag();
const expectedTag = 'cd33b28ac773f74ba00ed1f312572435';
expect(tag.toString('hex')).toBe(expectedTag);
});
});
4. FIPS 186-4 - Digital Signature Standard¶
RSA-4096 pour signatures¶
import { generateKeyPairSync, sign, verify } from 'crypto';
// ✅ CONFORME FIPS 186-4
class RSASignature {
generateKeyPair(): KeyPair {
return generateKeyPairSync('rsa', {
modulusLength: 4096, // FIPS 186-4: ≥ 2048 bits, 4096 recommandé
publicKeyEncoding: {
type: 'spki',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
},
});
}
signDocument(data: Buffer, privateKey: string): Buffer {
// RSA-PSS avec SHA3-256
return sign('sha3-256', data, {
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: 32, // SHA3-256 output size
});
}
verifySignature(
data: Buffer,
signature: Buffer,
publicKey: string
): boolean {
return verify('sha3-256', data, {
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: 32,
}, signature);
}
}
// ❌ NON CONFORME - RSA < 2048 bits
const keyPair = generateKeyPairSync('rsa', {
modulusLength: 1024, // INTERDIT (cassable)
});
5. Dérivation de clés¶
HKDF-SHA3-256 (RFC 5869 adapté)¶
import { hkdf } from '@noble/hashes/hkdf';
import { sha3_256 } from '@noble/hashes/sha3';
// ✅ CONFORME - HKDF avec SHA3-256
async function deriveKey(
masterKey: Buffer,
salt: Buffer,
info: string,
length: number
): Promise<Buffer> {
const derivedKey = hkdf(sha3_256, masterKey, salt, info, length);
return Buffer.from(derivedKey);
}
// Exemple: Dérivation clé document
const k_vault_user = Buffer.from('...'); // 256 bits
const doc_id = 'document-uuid-123';
const k_doc = await deriveKey(
k_vault_user,
Buffer.from(doc_id), // Salt unique par document
'ProbatioVault Document Encryption v1',
32 // 256 bits
);
Argon2id pour password hashing (RFC 9106)¶
import argon2 from 'argon2';
// ✅ CONFORME - Argon2id (recommandé OWASP, accepté NIST)
async function hashPassword(password: string): Promise<string> {
return argon2.hash(password, {
type: argon2.argon2id, // Résistant GPU + side-channel
memoryCost: 65536, // 64 MiB (OWASP recommendation)
timeCost: 3, // Iterations
parallelism: 4, // Threads
saltLength: 16, // 128 bits
hashLength: 32, // 256 bits
});
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return argon2.verify(hash, password);
}
// ❌ NON CONFORME - PBKDF2 insuffisant
import { pbkdf2Sync } from 'crypto';
const hash = pbkdf2Sync(password, salt, 100000, 32, 'sha256');
// Vulnérable attaques GPU/ASIC
6. Génération de nombres aléatoires¶
CSPRNG (Cryptographically Secure PRNG)¶
import { randomBytes } from 'crypto';
// ✅ CONFORME - CSPRNG FIPS 140-2 Annex C
function generateRandomKey(length: number): Buffer {
return randomBytes(length); // Utilise /dev/urandom (Linux) ou CryptGenRandom (Windows)
}
// Génération IV/nonce
const iv = randomBytes(12); // 96 bits pour AES-GCM
const salt = randomBytes(16); // 128 bits pour dérivation
// ❌ NON CONFORME - Math.random()
function generateWeakKey(): string {
return Math.random().toString(36); // NON cryptographique
}
Test d'entropie¶
// ✅ CONFORME - Vérification entropie
describe('CSPRNG Entropy Tests', () => {
it('should generate unique random values', () => {
const samples = 1000;
const randomValues = new Set<string>();
for (let i = 0; i < samples; i++) {
const random = randomBytes(32).toString('hex');
randomValues.add(random);
}
// Tous les échantillons doivent être uniques
expect(randomValues.size).toBe(samples);
});
it('should have uniform distribution', () => {
const samples = 10000;
const buckets = new Array(256).fill(0);
for (let i = 0; i < samples; i++) {
const random = randomBytes(1)[0];
buckets[random]++;
}
// Distribution approximativement uniforme (chi-square test)
const expected = samples / 256;
const chiSquare = buckets.reduce(
(sum, count) => sum + Math.pow(count - expected, 2) / expected,
0
);
// Chi-square critical value (p=0.05, df=255) ≈ 293
expect(chiSquare).toBeLessThan(300);
});
});
7. Algorithmes interdits¶
Liste noire FIPS¶
| Algorithme | Status | Raison |
|---|---|---|
| MD5 | ❌ INTERDIT | Collisions trouvées |
| SHA-1 | ❌ INTERDIT | Collisions possibles |
| DES | ❌ INTERDIT | Clé 56 bits (cassable) |
| 3DES | ❌ INTERDIT | Obsolète, vulnérabilités |
| RC4 | ❌ INTERDIT | Biaisé |
| AES-ECB | ❌ INTERDIT | Pas de sécurité sémantique |
| AES-CBC (sans HMAC) | ❌ INTERDIT | Pas d'authentification |
| RSA < 2048 bits | ❌ INTERDIT | Cassable |
Détection automatique¶
# Scan code pour algorithmes interdits
grep -r "md5\|sha1\|des\|rc4\|ecb" src/ --exclude-dir=node_modules
# Scan pour clés RSA faibles
grep -r "modulusLength.*: [0-9]\{3,\}" src/ | grep -v "4096\|3072\|2048"
# Scan pour Math.random() en contexte crypto
grep -r "Math.random()" src/crypto/
8. Matrice de conformité FIPS¶
| Exigence | Standard | Implémentation | Conforme |
|---|---|---|---|
| Modules cryptographiques | FIPS 140-2 L3 | AWS CloudHSM | ✅ |
| Hash probatoires | FIPS 202 | SHA3-256 | ✅ |
| Chiffrement symétrique | FIPS 197 + SP 800-38D | AES-256-GCM | ✅ |
| Chiffrement asymétrique | FIPS 186-4 | RSA-4096 | ✅ |
| Dérivation clés | SP 800-108 | HKDF-SHA3-256 | ✅ |
| Password hashing | - | Argon2id (RFC 9106) | ✅* |
| Génération aléatoire | FIPS 140-2 Annex C | randomBytes (CSPRNG) | ✅ |
| Test vectors | Tous standards | Implémentés | ✅ |
*Note: Argon2id n'est pas FIPS mais recommandé OWASP/ANSSI, acceptable pour ProbatioVault.
Checklist conformité FIPS¶
Avant mise en production¶
- CloudHSM FIPS 140-2 Level 3 configuré
- SHA3-256 (FIPS 202) pour tous les hash probatoires
- AES-256-GCM (FIPS 197 + SP 800-38D) pour chiffrement
- RSA-4096 (FIPS 186-4) pour signatures
- HKDF-SHA3-256 pour dérivation clés
- Argon2id pour password hashing
- CSPRNG (FIPS 140-2 Annex C) pour aléatoire
- Test vectors validés pour chaque algorithme
- Aucun algorithme interdit dans le code
- Documentation certification CloudHSM à jour
Exemples d'écarts BLOQUANTS¶
Écart : SHA-256 au lieu de SHA3-256¶
// ❌ BLOQUANT - SHA-256 (FIPS 180-4) au lieu de SHA3-256 (FIPS 202)
import { createHash } from 'crypto';
const hash = createHash('sha256').update(data).digest();
// ✅ CONFORME
import { sha3_256 } from '@noble/hashes/sha3';
const hash = sha3_256(data);
Gravité : BLOQUANT Raison : Non-conformité FIPS 202 requis pour ProbatioVault
Écart : Clé AES-128 au lieu de AES-256¶
// ❌ BLOQUANT - AES-128 (128 bits insuffisant)
const key = randomBytes(16); // 128 bits
const cipher = createCipheriv('aes-128-gcm', key, iv);
// ✅ CONFORME - AES-256
const key = randomBytes(32); // 256 bits
const cipher = createCipheriv('aes-256-gcm', key, iv);
Gravité : BLOQUANT Raison : AES-256 requis pour protection long terme (30 ans)
Écart : Math.random() pour crypto¶
// ❌ BLOQUANT - Math.random() non cryptographique
const token = Math.random().toString(36);
// ✅ CONFORME - CSPRNG
const token = randomBytes(32).toString('hex');
Gravité : BLOQUANT Raison : FIPS 140-2 Annex C - CSPRNG obligatoire
Escalade obligatoire¶
Escalader vers expert crypto/ANSSI humain si : - Besoin de certification FIPS formelle du module - Algorithme FIPS non disponible pour use case spécifique - Contradiction entre FIPS et autre standard (eIDAS, ANSSI) - Audit externe FIPS requis - Question sur acceptabilité d'un algorithme
Références normatives¶
- FIPS 140-2/140-3: Security Requirements for Cryptographic Modules
- FIPS 202: SHA-3 Standard
- FIPS 197: Advanced Encryption Standard (AES)
- FIPS 186-4: Digital Signature Standard (DSS)
- NIST SP 800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM)
- NIST SP 800-57: Recommendation for Key Management
- NIST SP 800-108: Recommendation for Key Derivation
- RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
- RFC 9106: Argon2 Memory-Hard Function for Password Hashing
Historique¶
| Version | Date | Changement |
|---|---|---|
| 1.0.0 | 2026-01-14 | Création initiale |