Mensaje de error
OperationError: The operation failed for an operation-specific reason
WebCrypto crypto.subtle — browsers & Node
Qué significa
Es el error genérico de WebCrypto, vago a propósito: falló la propia primitiva. En decrypt() con AES-GCM significa que la etiqueta de autenticación no se verificó: clave incorrecta, IV incorrecto, datos adicionales incorrectos o texto cifrado modificado. La especificación mantiene el mensaje genérico para que las implementaciones no revelen por qué falló una comprobación criptográfica. En sign() y deriveBits(), el mismo nombre abarca fallos internos de la primitiva, así que importa más la operación que aparece en la traza de pila que el texto del mensaje.
Por qué ocurre
Fallo de autenticación de AES-GCM
frecuenteDescifrar con una clave distinta de la que cifró, un IV que no coincide, additionalData ausente o distinto, o un texto cifrado que perdió por el camino la etiqueta de 16 bytes añadida al final. GCM es autenticado: cualquiera de estos casos hace fallar toda la operación en lugar de devolver datos basura.
Texto cifrado truncado o recodificado
frecuenteBase64 tratado de forma incoherente (alfabeto seguro para URL frente al estándar), una columna de la base de datos que recorta bytes o conversiones entre cadena y binario que corrompen el búfer. La comprobación de la etiqueta detecta cualquiera de estos cambios: para eso está.
Parámetros de derivación fuera de rango
ocasionalderiveBits/deriveKey con una longitud imposible de satisfacer, PBKDF2 con cero iteraciones o un cálculo ECDH sobre entradas incoherentes aparecen como OperationError en varios entornos de ejecución.
Cómo solucionarlo
- 1.
Enviar juntos el IV y el texto cifrado, y decodificar de forma simétrica
Antepón el IV al texto cifrado y sepáralos al descifrar, para que ambos lados coincidan siempre; usa la misma variante de base64 en todas partes.
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.
Tratarlo como un veredicto de integridad, no como corrupción
Cuando decrypt lanza OperationError, la respuesta correcta es «este texto cifrado no es auténtico con esta clave»: recházalo. No reintentes con ajustes del relleno ni recurras a modos sin autenticación; que la comprobación falle es precisamente la medida de seguridad.
- 3.
Comparar las huellas digitales de las claves en ambos lados
Exporta ambas claves y calcula su hash; si los resúmenes difieren, el misterio se resuelve en un solo paso.
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