Saltar al contenido
ecdsa.com
WebCrypto crypto.subtleWebCrypto

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

Cómo solucionarlo

  1. 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. 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. 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

Errores relacionados

Explorar toda la base de datos de errores de firma