Mensaje de error
java.security.SignatureException: Invalid encoding for signature
El detalle de `Caused by` varía (por ejemplo, «Invalid lenByte» o «Not the correct tag») según el byte que rompió el análisis DER. El error contrario es silencioso: una firma DER pasada a `SHA256withECDSAinP1363Format` no lanza ninguna excepción, simplemente la verificación devuelve `false`.
Java (JDK) — Signature.verify with SHA256withECDSA (SunEC)
Qué significa
`SHA256withECDSA` espera una firma ECDSA en ASN.1 DER (`30 … 02 r 02 s`), y los bytes que le pasas no son DER. Casi siempre están en la otra codificación estándar: la concatenación r‖s de longitud fija (IEEE P1363) que usan JWS, WebCrypto y muchas bibliotecas que no son de Java; con P-256 son 64 bytes. El JDK también puede verificar ese formato con el nombre de algoritmo `SHA256withECDSAinP1363Format`.
Por qué ocurre
Firma r‖s en bruto verificada como DER
frecuenteLas firmas de un JWT (ES256), de `crypto.subtle.sign`, de código que concatena r y s a mano o de herramientas de blockchain son 64/96/132 bytes en bruto. Los nombres de algoritmo ECDSA predeterminados de Java esperan DER.
Los bytes de la firma se decodificaron mal
ocasionalUn segmento JWS en base64url decodificado con el decodificador básico (tras sustituir mal los caracteres), o datos hexadecimales decodificados como base64, producen bytes que no son ninguna firma.
Una firma RSA pasada a un verificador ECDSA
ocasionalUna firma RSA de 256 bytes tampoco es DER. Comprueba el algoritmo del token o del documento antes de elegir el verificador.
Cómo solucionarlo
- 1.
Verificar las firmas en bruto con el algoritmo P1363
Disponible desde JDK 9 en el proveedor SunEC para SHA-1/224/256/384/512 con ECDSA. No hace falta ninguna conversión.
java // JWS (ES256) and WebCrypto subtle.sign() produce raw r||s; WebAuthn and X.509 use DER. Signature verifier = Signature.getInstance("SHA256withECDSAinP1363Format"); verifier.initVerify(publicKey); verifier.update(signedBytes); boolean ok = verifier.verify(rawSignature); // 64 bytes for P-256 - 2.
O convertir r‖s a DER
Cuando una API exige DER (por ejemplo, un proveedor de HSM), envuelve r y s como INTEGER DER mínimos dentro de una SEQUENCE. El conversor entre DER y r‖s en bruto comprueba tu conversión.
java static byte[] p1363ToDer(byte[] raw) { int n = raw.length / 2; byte[] r = derInteger(java.util.Arrays.copyOfRange(raw, 0, n)); byte[] s = derInteger(java.util.Arrays.copyOfRange(raw, n, raw.length)); var out = new java.io.ByteArrayOutputStream(); out.write(0x30); out.write(r.length + s.length); // < 128 for P-256 and P-384 out.writeBytes(r); out.writeBytes(s); return out.toByteArray(); } static byte[] derInteger(byte[] v) { int i = 0; while (i < v.length - 1 && v[i] == 0) i++; boolean pad = (v[i] & 0x80) != 0; byte[] out = new byte[2 + (pad ? 1 : 0) + v.length - i]; out[0] = 0x02; out[1] = (byte) (out.length - 2); System.arraycopy(v, i, out, pad ? 3 : 2, v.length - i); return out; }