jwtk/jjwt · error · io.jsonwebtoken.security.InvalidKeyException
Invalid ${id} ASN.1 encoding: ${t.getMessage()}
Error message
Invalid ${id} ASN.1 encoding: ${t.getMessage()} What it means
Edwards curve keys (Ed25519/Ed448/X25519/X448) are stored and exchanged via a fixed ASN.1 (PKCS#8/SubjectPublicKeyInfo-style) encoding prefixed by a curve-specific DER header. When EdwardsCurve.getKeyMaterial parses a key's encoded bytes and the ASN.1 structure fails to decode (or is out of bounds), the raw cause is wrapped into an InvalidKeyException with this message.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java:200
this.PUBLIC_KEY_ASN1_PREFIX = publicKeyAsn1Prefix(this.encodedKeyByteLength, this.ASN1_OID);
this.PRIVATE_KEY_ASN1_PREFIX = privateKeyPkcs8Prefix(this.encodedKeyByteLength, this.ASN1_OID, true);
this.PRIVATE_KEY_JDK11_PREFIX = privateKeyPkcs8Prefix(this.encodedKeyByteLength, this.ASN1_OID, false);
}
@Override
public int getKeyBitLength() {
return this.keyBitLength;
}
public byte[] getKeyMaterial(Key key) {
try {
return doGetKeyMaterial(key); // can throw assertion and ArrayIndexOutOfBound exception on invalid input
} catch (Throwable t) {
if (t instanceof KeyException) { //propagate
throw (KeyException) t;
}
String msg = "Invalid " + getId() + " ASN.1 encoding: " + t.getMessage();
throw new InvalidKeyException(msg, t);
}
}
/**
* Parses the ASN.1-encoding of the specified key
*
* @param key the Edwards curve key
* @return the key value, encoded according to <a href="https://www.rfc-editor.org/rfc/rfc8032">RFC 8032</a>
* @throws RuntimeException if the key's encoded bytes do not reflect a validly ASN.1-encoded edwards key
*/
protected byte[] doGetKeyMaterial(Key key) {
byte[] encoded = KeysBridge.getEncoded(key);
try {
int i = Bytes.indexOf(encoded, ASN1_OID);
Assert.gt(i, -1, "Missing or incorrect algorithm OID.");
i = i + ASN1_OID.length;
int keyLen = 0;
if (encoded[i] == 0x05) { // NULL terminator, next should be zero byte indicatorView on GitHub (pinned to fb71496164)
Solutions
- Regenerate or re-export the key in standard PKCS#8 (private) / X.509 SPKI (public) DER format compatible with the curve.
- Do not strip or manually prepend the ASN.1 prefix bytes; let jjwt/JCE encode the key.
- Inspect the exception's cause (t) to see the exact ASN.1 parse failure and fix the encoding.
- Verify the key is actually an Edwards-curve key, not an ordinary EC key.
Example fix
// before: building a private key from raw seed bytes with wrong wrapping PrivateKey key = new RawEdPrivateKey(seedBytes); // after KeyPair kp = Jwts.SIG.EdDSA.keyPair().build(); PrivateKey key = kp.getPrivate();
Defensive patterns
Strategy: try-catch
Validate before calling
byte[] enc = key.getEncoded();
if (enc == null || enc.length < 16) throw new IllegalArgumentException("Key has no/short encoded form; expected PKCS#8 or SPKI DER"); Try / catch
try {
PublicKey pub = EdwardsCurve.Ed25519.toPublicKey(xBytes, null);
} catch (InvalidKeyException e) {
// cause holds the ASN.1 parse error; fix the encoding
Throwable cause = e.getCause();
} Prevention
- Export keys in standard DER (PKCS#8/SPKI) formats
- Do not strip or hand-craft ASN.1 prefix bytes
- Verify key is an Edwards-curve key before parsing
When it happens
Trigger: Passing a key whose encoded bytes do not follow the expected ASN.1 layout for the curve — e.g. a key generated/serialized by a different library format, an Ed25519 key bytes truncated or prefixed incorrectly, or feeding a non-Edwards key's bytes into EdwardsCurve parsing via findByKey/pkBytes/d/x.
Common situations: Interoperability with OpenSSL or other libraries that export keys in a different DER layout; manually constructing PrivateKey objects from raw bytes without the DER prefix; copy-paste corruption of base64 key material; using a P-256 EC key where an OKP key is expected.
Related errors
- Invalid ${id} encoded ${PublicKey|PrivateKey} length. Should
- PrivateKeys may not be used to verify digital signatures. Pr
- PublicKeys may not be used to decrypt data. PublicKeys are u
- JWS verification key must be either a SecretKey (for MAC alg
- Unable to create ${type.getSimpleName()} from JWK ${ctx}: ${
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/9ec6f20e2174827e.
Report an issue: GitHub.