# @mostajs/crypto-box — 0.1.0
Auteur : Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later · Niveau N0 · ZÉRO dépendance

RÔLE
  LES primitives cryptographiques de l'écosystème — une seule maison, un seul endroit à durcir.
  Enveloppe MINCE et opinionée sur node:crypto. PAS une bibliothèque de crypto : aucun choix
  d'algorithme, aucun mode dangereux, aucun IV fourni par l'appelant.

MOTIF
  La même comparaison de signature existait 2x : « best effort » dans @mostajs/url (le KERNEL)
  et correcte dans @mostajs/storage (une feuille). Le durcissement n'avait pas circulé.

API
  sha256(data, 'hex'|'base64url')        -> string
  sha256Bytes(data)                      -> Buffer      (chaînages)
  hmacSha256(key, data, enc)             -> string
  hmacSha256Bytes(key, data)             -> Buffer      (chaînage SigV4)
  equalsConstantTime(a, b)               -> boolean     TOUTE comparaison de secret passe ici
  deriveKey(passphrase, {salt?, cost?})  -> {key(32o), salt(16o)}   scrypt, N=2^17 par défaut
  randomKey(bytes=32)                    -> Buffer
  aeadEncrypt(key32, plaintext)          -> Buffer      AES-256-GCM, format MJSC1|iv|tag|chiffré
  aeadDecrypt(key32, blob)               -> Buffer      LÈVE si clé fausse OU 1 bit altéré

GARANTIES
  - AEAD = confidentialité ET intégrité. Un bit modifié → échec (tag GCM).
  - IV aléatoire à chaque appel, jamais fourni par l'appelant (réutilisation d'IV en GCM =
    catastrophe : révèle le XOR des clairs, permet de forger).
  - Format autoportant : rien à conserver hors la clé.
  - equalsConstantTime ne plante pas sur longueurs différentes (timingSafeEqual de Node lève).

HORS PÉRIMÈTRE
  La garde de la clé = décision produit. TicketFlow : clé chez le CLIENT, la console ne stocke
  que du chiffré illisible pour elle. Clé perdue = archive irrécupérable (à contractualiser).

TESTS
  18 tests mjs-unit. Vecteurs vérifiés indépendamment (sha256 coreutils, HMAC RFC 4231 cas 1).
