Mensagem de erro
java.security.SignatureException: Invalid encoding for signature
O detalhe do `Caused by` varia (por exemplo, “Invalid lenByte” ou “Not the correct tag”) conforme o byte que quebrou a análise do DER. O erro inverso é silencioso: uma assinatura DER passada para `SHA256withECDSAinP1363Format` não lança exceção, a verificação simplesmente retorna `false`.
Java (JDK) — Signature.verify with SHA256withECDSA (SunEC)
O que significa
O `SHA256withECDSA` espera uma assinatura ECDSA em ASN.1 DER (`30 … 02 r 02 s`), e os bytes que você passou não estão em DER. Em quase todos os casos, eles estão na outra codificação padrão: a concatenação r‖s de tamanho fixo (IEEE P1363), usada por JWS, WebCrypto e muitas bibliotecas fora do mundo Java — 64 bytes para P-256. O JDK também consegue verificar esse formato, com o nome de algoritmo `SHA256withECDSAinP1363Format`.
Por que acontece
Assinatura r‖s bruta verificada como DER
comumAssinaturas de um JWT (ES256), de `crypto.subtle.sign`, de código que concatena r e s à mão ou de ferramentas de blockchain são 64/96/132 bytes brutos. Os nomes de algoritmo ECDSA padrão do Java esperam DER.
Os bytes da assinatura foram decodificados incorretamente
ocasionalUm segmento JWS em base64url decodificado com o decodificador básico (depois de uma substituição malfeita de caracteres), ou hex decodificado como base64, produz bytes que não são assinatura nenhuma.
Uma assinatura RSA entregue a um verificador ECDSA
ocasionalUma assinatura RSA de 256 bytes também não é DER. Confira o algoritmo do token ou do documento antes de escolher o verificador.
Como corrigir
- 1.
Verificar assinaturas brutas com o algoritmo P1363
Disponível desde o JDK 9 no provedor SunEC para SHA-1/224/256/384/512 com ECDSA. Nenhuma conversão é necessária.
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.
Ou converter r‖s para DER
Quando uma API exige DER (por exemplo, um provedor de HSM), encapsule r e s como INTEGERs DER mínimos dentro de uma SEQUENCE. O conversor DER ⇄ bruto confere sua conversão.
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; }