Message d’erreur
OperationError: The operation failed for an operation-specific reason
WebCrypto crypto.subtle — browsers & Node
Ce que cela signifie
L’erreur générique de WebCrypto, volontairement vague : la primitive elle-même a échoué. Pour decrypt() avec AES-GCM, cela signifie que la vérification du tag d’authentification a échoué (mauvaise clé, mauvais IV, mauvaises données additionnelles ou texte chiffré modifié). La spécification garde un message générique pour que les implémentations ne révèlent pas pourquoi un contrôle cryptographique a échoué. Pour sign() et deriveBits(), le même nom couvre les échecs internes de la primitive : l’opération qui figure dans votre trace de pile compte donc davantage que le texte du message.
Pourquoi cela se produit
Échec d’authentification AES-GCM
fréquenteDéchiffrer avec une autre clé que celle du chiffrement, un IV différent, des additionalData absentes ou différentes, ou un texte chiffré qui a perdu pendant le transport son tag de 16 octets ajouté en fin. GCM est authentifié : chacun de ces cas fait échouer toute l’opération au lieu de renvoyer des données inexploitables.
Texte chiffré tronqué ou réencodé
fréquenteBase64 traité de manière incohérente (alphabet URL-safe contre alphabet standard), une colonne de base de données qui tronque des octets, ou des conversions chaîne/binaire qui corrompent le tampon. La vérification du tag détecte chacune de ces modifications : c’est son rôle.
Paramètres de dérivation hors limites
occasionnellederiveBits/deriveKey avec une longueur impossible à satisfaire, PBKDF2 avec zéro itération ou un calcul ECDH sur des entrées incohérentes se manifestent par une OperationError dans plusieurs environnements d’exécution.
Comment corriger l’erreur
- 1.
Transmettre l’IV et le texte chiffré ensemble, décoder de façon symétrique
Placez l’IV devant le texte chiffré et séparez-les au déchiffrement, pour que les deux côtés soient toujours d’accord ; utilisez la même variante de base64 partout.
js // encrypt const iv = crypto.getRandomValues(new Uint8Array(12)); const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data); const packed = new Uint8Array([...iv, ...new Uint8Array(ct)]); // decrypt const buf = packedFromWire; const pt = await crypto.subtle.decrypt( { name: "AES-GCM", iv: buf.slice(0, 12) }, key, buf.slice(12), ); - 2.
Le traiter comme un verdict d’intégrité, pas comme une corruption
Lorsque decrypt lève une OperationError, la réponse correcte est « ce texte chiffré n’est pas authentique avec cette clé » : rejetez-le. Ne réessayez pas en ajustant le remplissage et ne vous rabattez pas sur des modes non authentifiés ; l’échec de la vérification est précisément la fonction de sécurité.
- 3.
Comparer les empreintes des clés des deux côtés
Exportez les deux clés et hachez-les ; des condensats différents lèvent le mystère en une seule étape.
js const raw = await crypto.subtle.exportKey("raw", key); const fp = await crypto.subtle.digest("SHA-256", raw); console.log(Buffer.from(fp).toString("hex").slice(0, 16)); // compare on both sides