jwtk/jjwt · error · io.jsonwebtoken.security.InvalidKeyException
Unable to derive Edwards-curve PublicKey for specified…
Error message
Unable to derive Edwards-curve PublicKey for specified PrivateKey: ${privateKey} What it means
EdwardsPublicKeyDeriver computes the PublicKey corresponding to a supplied Edwards-curve PrivateKey (needed for X25519 key agreement with only a private key). It first resolves the key's curve via EdwardsCurve.findByKey; if no curve matches, it throws an InvalidKeyException saying the public key cannot be derived.
Solutions
- Pass an actual X25519/X448/Ed25519/Ed448 PrivateKey; generate with Jwts.SIG.X25519.keyPair() etc.
- Check the key's algorithm string and encoded bytes before calling; only OKP keys are supported here.
- Re-export/re-import the key in standard PKCS#8 format so it can be recognized.
- Verify a JCE provider supporting the curve is installed.
Example fix
// before PublicKey pub = deriver.apply(ecPrivateKey); // after KeyPair kp = Jwts.SIG.X25519.keyPair().build(); PublicKey pub = deriver.apply(kp.getPrivate());
Defensive patterns
Strategy: validation
Validate before calling
EdwardsCurve curve = EdwardsCurve.findByKey(privateKey);
if (curve == null) throw new IllegalArgumentException("Cannot derive public key: not an Edwards private key"); Type guard
boolean isEdwardsPrivateKey(PrivateKey k) {
return EdwardsCurve.findByKey(k) != null;
} Try / catch
try {
PublicKey pub = new EdwardsPublicKeyDeriver().apply(privateKey);
} catch (InvalidKeyException e) {
// pass a proper OKP private key instead
} Prevention
- Only pass X25519/X448/Ed25519/Ed448 private keys to the deriver
- Import keys in standard PKCS#8 format
- Verify provider support for the curve
When it happens
Trigger: Calling apply(privateKey) (e.g. during ECDH-ES sender-side epk generation) with a PrivateKey that is not an Edwards curve key, or an Edwards key whose encoding the resolver cannot recognize.
Common situations: Passing an EC or RSA private key into an X25519/EdDSA key-agreement flow; keys loaded from PKCS#12/PEM with unexpected formats; provider incompatibilities making the key's encoded form unrecognizable.
Related errors
- Unable to derive RSAPublicKey from RSAPrivateKey
- Unrecognized Edwards Curve key
- derivedKeyBitLength may not exceed
- keys must be s (implement ). Provided key type: .
- Invalid ASN.1 encoding
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/d2a9fb4bb046b080.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsPublicKeyDeriver.java:44
/**
* Derives a PublicKey from an Edwards-curve PrivateKey instance.
*/
final class EdwardsPublicKeyDeriver implements Function<PrivateKey, PublicKey> {
public static final Function<PrivateKey, PublicKey> INSTANCE = new EdwardsPublicKeyDeriver();
private EdwardsPublicKeyDeriver() {
// prevent public instantiation.
}
@Override
public PublicKey apply(PrivateKey privateKey) {
EdwardsCurve curve = EdwardsCurve.findByKey(privateKey);
if (curve == null) {
String msg = "Unable to derive Edwards-curve PublicKey for specified PrivateKey: " + KeysBridge.toString(privateKey);
throw new InvalidKeyException(msg);
}
byte[] pkBytes = curve.getKeyMaterial(privateKey);
// This is a hack that utilizes the JCE implementations' behavior of using an RNG to generate a new private
// key, and from that, the implementation computes a public key from the private key bytes.
// Since we already have a private key, we provide a RNG that 'generates' the existing private key
// instead of a random one, and the corresponding public key will be computed for us automatically.
SecureRandom random = new ConstantRandom(pkBytes);
KeyPair pair = curve.keyPair().random(random).build();
Assert.stateNotNull(pair, "Edwards curve generated keypair cannot be null.");
return Assert.stateNotNull(pair.getPublic(), "Edwards curve KeyPair must have a PublicKey");
}
private static final class ConstantRandom extends SecureRandom {
private final byte[] value;
public ConstantRandom(byte[] value) {View on GitHub (pinned to fb71496164)