Error message
java.security.SignatureException: Invalid encoding for signature
The `Caused by` detail varies (for example "Invalid lenByte" or "Not the correct tag") depending on which byte broke DER parsing. The opposite mistake is silent: a DER signature passed to `SHA256withECDSAinP1363Format` does not throw, it just verifies as `false`.
Java (JDK) — Signature.verify with SHA256withECDSA (SunEC)
What it means
`SHA256withECDSA` expects an ECDSA signature in ASN.1 DER (`30 … 02 r 02 s`), and the bytes you passed are not DER. In almost every case they are the other standard encoding: the fixed-length r‖s concatenation (IEEE P1363) used by JWS, WebCrypto and many non-Java libraries — 64 bytes for P-256. The JDK can verify that format too, under the algorithm name `SHA256withECDSAinP1363Format`.
Why it happens
Raw r‖s signature verified as DER
commonSignatures from a JWT (ES256), from `crypto.subtle.sign`, from code that concatenates r and s by hand, or from blockchain tooling are 64/96/132 raw bytes. Java's default ECDSA algorithm names expect DER.
The signature bytes were decoded incorrectly
occasionalA base64url JWS segment decoded with the basic decoder (after replacing characters badly), or hex decoded as base64, produces bytes that are no signature at all.
An RSA signature given to an ECDSA verifier
occasionalA 256-byte RSA signature is not DER either. Check the token's or document's algorithm before choosing the verifier.
How to fix it
- 1.
Verify raw signatures with the P1363 algorithm
Available since JDK 9 in the SunEC provider for SHA-1/224/256/384/512 with ECDSA. No conversion needed.
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.
Or convert r‖s to DER
When an API insists on DER (for example an HSM provider), wrap r and s as minimal DER INTEGERs inside a SEQUENCE. The DER ⇄ raw converter checks your conversion.
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; }