Saltar al contenido
ecdsa.com
WebCrypto SubtleCrypto.exportKey / wrapKeyWebCrypto

Mensaje de error

InvalidAccessError: Failed to execute 'exportKey' on 'SubtleCrypto': key is not extractable

También se muestra como

  • InvalidAccessError: The CryptoKey is nonextractable
  • InvalidAccessError: A parameter or an operation is not supported by the underlying object

Arriba está el texto de Chromium; Safari/WebKit: «The CryptoKey is nonextractable»; Firefox: «A parameter or an operation is not supported by the underlying object». En todos los casos es una DOMException `InvalidAccessError`.

WebCrypto SubtleCrypto.exportKey / wrapKey — DOMException InvalidAccessError (Chromium / Firefox / WebKit)

Qué significa

La clave se creó con `extractable: false`, así que su material nunca se puede volver a leer: ni con `exportKey` ni con `wrapKey`. Ese es el propósito del indicador: la clave privada se queda dentro de la implementación criptográfica del navegador, y los scripts (incluidos los inyectados) pueden usarla, pero no robarla. Las claves públicas de un par generado siempre se pueden exportar; este error afecta a las claves privadas y a las claves secretas.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Conservar la clave privada como objeto y exportar la clave pública

    Guarda las claves no extraíbles como objetos `CryptoKey` en IndexedDB y comparte solo la clave pública (SPKI o JWK). Así se mantiene la protección que aporta el indicador.

    js
    const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, false, ["sign", "verify"]);
    // Persist the non-extractable private key as a CryptoKey object (structured clone), never as bytes:
    await idbPut("signing-key", pair.privateKey);
    // Share only the public key:
    const jwk = await crypto.subtle.exportKey("jwk", pair.publicKey);
  2. 2.

    Crear claves extraíbles solo cuando la exportación sea un requisito

    Si la clave privada realmente tiene que salir del navegador, genérala como extraíble y expórtala solo envuelta con otra clave.

    js
    // Only if the private key must leave the browser (e.g. a user-initiated, encrypted backup):
    const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
    const wrapped = await crypto.subtle.wrapKey("pkcs8", pair.privateKey, backupKey, { name: "AES-GCM", iv });

Errores relacionados

Explorar toda la base de datos de errores de firma