Chiffrement
Chiffrement symétrique AES-256-GCM des secrets applicatifs stockés en base, tokens tiers, secrets de webhooks.
core/crypto chiffre les valeurs sensibles qui doivent être stockées en base et relues en clair : token d'API d'un service tiers, secret de webhook, identifiants d'un connecteur. Ce sont les cas où un hachage à sens unique ne convient pas parce qu'il faut retrouver la valeur d'origine.
Pour un mot de passe utilisateur, ne pas utiliser ce module : core/users hache avec hashPassword.
Import
import { isEncryptionAvailable, encryptSecret, decryptSecret } from '@lrvo/core/crypto';Module serveur : il lit LRVO_ENCRYPTION_KEY et utilise node:crypto.
Variables d'environnement
| Variable | Obligatoire | Rôle |
|---|---|---|
LRVO_ENCRYPTION_KEY | dès qu'un module utilise ce core | Clé maîtresse, 64 caractères hexadécimaux (32 octets). |
npx @lrvo/start remplit cette variable à la création du projet. Sur un projet monté à la main, générer une clé :
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"API
isEncryptionAvailable()
Retourne true si la clé est définie et bien formée, sans jamais lever. Sert aux chemins qui doivent se désactiver plutôt que crasher quand la clé manque, typiquement la vérification d'activation d'un module.
if (!isEncryptionAvailable()) {
return { enabled: false, reason: 'LRVO_ENCRYPTION_KEY absente' };
}encryptSecret(plain)
Chiffre une chaîne UTF-8 et retourne la valeur encodée. Lève si la clé est absente ou mal formée, ou si l'argument n'est pas une chaîne.
const stored = encryptSecret(apiToken);
await updateById('lrvo_blog_connectors', id, { token: stored });decryptSecret(encoded)
Déchiffre une valeur produite par encryptSecret. Lève si la clé est absente, si le format est invalide, ou si le tag d'authentification ne correspond pas : ce dernier cas signale que la valeur a été altérée ou chiffrée avec une autre clé.
const row = await findById('lrvo_blog_connectors', id);
const apiToken = decryptSecret(row.token);Format stocké
"<iv_b64>:<tag_b64>:<ciphertext_b64>"Trois champs séparés par :, chacun en base64 standard. L'algorithme est AES-256-GCM, avec un IV de 12 octets tiré aléatoirement à chaque chiffrement et un tag d'authentification de 16 octets. Deux chiffrements de la même valeur produisent donc deux chaînes différentes, ce qui empêche de reconnaître deux secrets identiques en comparant les colonnes.
La colonne qui reçoit cette valeur doit accepter du texte de longueur variable (TEXT), pas une taille fixe.
Notes
La rotation de clé impose de tout re-chiffrer. Il n'y a pas de mécanisme de versionnage de clé : changer LRVO_ENCRYPTION_KEY rend illisible tout ce qui a été chiffré avec l'ancienne. Traiter la clé comme permanente pour un déploiement donné, sauf à planifier une migration qui déchiffre avec l'ancienne clé et re-chiffre avec la nouvelle.
La clé n'a pas sa place dans le dépôt. Elle vit dans le .env du serveur, comme tout secret. Voir Sécurité.
La clé est mise en cache en mémoire tant que la valeur de la variable d'environnement ne change pas, donc l'appel répété de encryptSecret ne re-parse pas la clé à chaque fois.