@syldel/crypto-utils 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,7 +100,7 @@ try {
100
100
  - `open` refuses a token above 2 MiB, `seal` a plaintext above `JweUtil.MAX_PLAINTEXT_BYTES` (1 MiB), before any decoding.
101
101
  - A missing, non-hex or wrongly sized key throws `Invalid key: …`, never `Decryption failed`: it is a configuration error, and blaming the payload sent the search the wrong way. The message never quotes the key.
102
102
  - `PureJwtUtil.verify` only accepts `alg: "HS256"`, a JSON object payload, a numeric `exp`, and the canonical base64url spelling of the signature.
103
- - Both `sign` and `verify` refuse an empty or missing secret: HMAC happily signs with an empty key, which anyone can guess.
103
+ - Both `sign` and `verify` require a secret of exactly 64 hex characters, the form `crypto.randomBytes(32).toString('hex')` produces: 256 bits of randomness, the HS256 output size (OWASP JWT Cheat Sheet, RFC 8725 §3.5). HMAC happily signs with an empty key or a passphrase, which anyone can guess, and a length alone does not prove randomness. The secret is used as is, its 64 ASCII bytes, not decoded.
104
104
  - `nbf`, `iat`, `aud` and `iss` are **not** checked: callers that rely on them must check them themselves.
105
105
 
106
106
  ### ⚠️ Known limit: the master key lives in plain text
package/dist/jwt.util.js CHANGED
@@ -94,13 +94,28 @@ class PureJwtUtil {
94
94
  }
95
95
  exports.PureJwtUtil = PureJwtUtil;
96
96
  /**
97
- * createHmac signe avec une chaîne vide (mesuré sur le bot le 2026-10-06) : la
98
- * signature attendue devient calculable par quiconque devine le secret vide.
97
+ * Le secret doit être exactement 64 caractères hexadécimaux : la forme que
98
+ * produit `crypto.randomBytes(32).toString('hex')`, soit 256 bits d'aléa, la
99
+ * taille de sortie de HS256 (fiche JWT de l'OWASP, section MAC ; RFC 8725
100
+ * §3.5, qui interdit un mot de passe comme clé). Ce qui compte, c'est l'aléa,
101
+ * qu'une longueur seule ne prouve pas : « ceci-est-mon-mot-de-passe-de-prod »
102
+ * fait 33 octets. 64 caractères hexadécimaux ne se tapent pas à la main.
103
+ *
104
+ * Il sert tel quel de clé HMAC (ses 64 octets ASCII), sans être décodé :
105
+ * le décoder changerait toutes les signatures échangées entre les services.
106
+ *
107
+ * Un secret vide est refusé à part : createHmac signe avec une chaîne vide
108
+ * (mesuré sur le bot le 2026-10-06).
99
109
  */
110
+ const SECRET_PATTERN = /^[0-9a-fA-F]{64}$/;
100
111
  function assertSecret(secret) {
101
112
  if (typeof secret !== 'string' || secret.length === 0) {
102
113
  throw new Error('Invalid secret: a non-empty string is required');
103
114
  }
115
+ if (!SECRET_PATTERN.test(secret)) {
116
+ const allHex = /^[0-9a-fA-F]*$/.test(secret);
117
+ throw new Error(`Invalid secret: 64 hex characters required, got ${secret.length} characters${allHex ? '' : ', not all hex'} (generate it with crypto.randomBytes(32).toString('hex'))`);
118
+ }
104
119
  }
105
120
  function parseJsonObject(segment, error) {
106
121
  let value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syldel/crypto-utils",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Lightweight JWT and JWE (AES-256-GCM) utilities",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",