Fehlermeldung
java.security.SignatureException: Invalid encoding for signature
Das Detail unter `Caused by` variiert (zum Beispiel „Invalid lenByte“ oder „Not the correct tag“), je nachdem, an welchem Byte das DER-Parsing gescheitert ist. Der umgekehrte Fehler fällt nicht auf: Eine DER-Signatur, die an `SHA256withECDSAinP1363Format` übergeben wird, wirft keine Exception, sondern liefert bei der Prüfung einfach `false`.
Java (JDK) — Signature.verify with SHA256withECDSA (SunEC)
Was der Fehler bedeutet
`SHA256withECDSA` erwartet eine ECDSA-Signatur in ASN.1 DER (`30 … 02 r 02 s`), und die Bytes, die du übergeben hast, sind kein DER. Fast immer handelt es sich um die andere Standardkodierung: die Verkettung r‖s mit fester Länge (IEEE P1363), die JWS, WebCrypto und viele Bibliotheken außerhalb von Java verwenden – 64 Byte für P-256. Auch dieses Format kann das JDK prüfen, unter dem Algorithmusnamen `SHA256withECDSAinP1363Format`.
Warum der Fehler auftritt
Rohe r‖s-Signatur als DER geprüft
häufigSignaturen aus einem JWT (ES256), aus `crypto.subtle.sign`, aus Code, der r und s von Hand verkettet, oder aus Blockchain-Tools bestehen aus 64/96/132 rohen Bytes. Die Standardnamen der ECDSA-Algorithmen in Java erwarten DER.
Die Signaturbytes wurden falsch dekodiert
gelegentlichEin base64url-Segment eines JWS, das mit dem Basic-Decoder dekodiert wurde (nachdem Zeichen fehlerhaft ersetzt wurden), oder Hex, das als base64 dekodiert wurde, ergibt Bytes, die überhaupt keine Signatur sind.
Eine RSA-Signatur, an einen ECDSA-Verifier übergeben
gelegentlichEine 256-Byte-RSA-Signatur ist ebenfalls kein DER. Prüfe den Algorithmus des Tokens oder Dokuments, bevor du den Verifier auswählst.
So behebst du den Fehler
- 1.
Rohe Signaturen mit dem P1363-Algorithmus prüfen
Seit JDK 9 im Provider SunEC für SHA-1/224/256/384/512 mit ECDSA verfügbar. Keine Konvertierung nötig.
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.
Oder r‖s in DER konvertieren
Besteht eine API auf DER (zum Beispiel ein HSM-Provider), verpacke r und s als minimale DER-INTEGERs in einer SEQUENCE. Der Konverter DER ⇄ Raw prüft deine Umwandlung.
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; }