Jwt with ECDSA algorithms

With generated keys

Generation

import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.spec.{ECPrivateKeySpec, ECPublicKeySpec, ECGenParameterSpec, ECParameterSpec, ECPoint}
import java.security.{SecureRandom, KeyFactory, KeyPairGenerator, Security}
import pdi.jwt.{Jwt, JwtAlgorithm}
// We specify the curve we want to use
val ecGenSpec = new ECGenParameterSpec("P-521")
// We are going to use a ECDSA algorithm
// and the Bouncy Castle provider
if (Security.getProvider("BC") == null) {
  Security.addProvider(new BouncyCastleProvider())
}
val generatorEC = KeyPairGenerator.getInstance("ECDSA", "BC")
generatorEC.initialize(ecGenSpec, new SecureRandom())
// Generate a pair of keys, one private for encoding
// and one public for decoding
val ecKey = generatorEC.generateKeyPair()

Usage

val token = Jwt.encode("""{"user":1}""", ecKey.getPrivate, JwtAlgorithm.ES512)

Jwt.decode(token, ecKey.getPublic, JwtAlgorithm.allECDSA)

With saved keys

Let’s say you already have your keys, it means you know the S param for the private key and both (X, Y) for the public key. So we will first recreate the keys from those params and then use them just as we did for the previously generated keys.

Creation

import org.bouncycastle.jce.ECNamedCurveTable
import org.bouncycastle.jce.spec.ECNamedCurveSpec

// Our saved params
val S = BigInt("1ed498eedf499e5dd12b1ab94ee03d1a722eaca3ed890630c8b25f1015dd4ec5630a02ddb603f3248a3b87c88637e147ecc7a6e2a1c2f9ff1103be74e5d42def37d", 16)
val X = BigInt("16528ac15dc4c8e0559fad628ac3ffbf5c7cfefe12d50a97c7d088cc10b408d4ab03ac0d543bde862699a74925c1f2fe7c247c00fddc1442099dfa0671fc032e10a", 16)
val Y = BigInt("b7f22b3c1322beef766cadd1a5f0363840195b7be10d9a518802d8d528e03bc164c9588c5e63f1473d05195510676008b6808508539367d2893e1aa4b7cb9f9dab", 16)

// Here we are using the P-521 curve but you need to change it
// to your own curve
val curveParams = ECNamedCurveTable.getParameterSpec("P-521")
val curveSpec: ECParameterSpec = new ECNamedCurveSpec( "P-521", curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());

val privateSpec = new ECPrivateKeySpec(S.underlying(), curveSpec)
val publicSpec = new ECPublicKeySpec(new ECPoint(X.underlying(), Y.underlying()), curveSpec)

val privateKeyEC = KeyFactory.getInstance("ECDSA", "BC").generatePrivate(privateSpec)
val publicKeyEC = KeyFactory.getInstance("ECDSA", "BC").generatePublic(publicSpec)

Usage

val token = Jwt.encode("""{"user":1}""", privateKeyEC, JwtAlgorithm.ES512)

Jwt.decode(token, publicKeyEC, Seq(JwtAlgorithm.ES512))

// Wrong key...
Jwt.decode(token, ecKey.getPublic, Seq(JwtAlgorithm.ES512))