Supporting Ed25519 and JWS.
This small project shows how to use Google Tink alongside Nimbus JOSE to support the Ed25519 public-key signature as it is becoming more and more popular and used in distributed ledgers.
The standard Java SDK will only support natively EdDSA from version 15, see JEP 339, whose general
availability will be on 15th, Sept, 2020.
The proposed implementation uses BouncyCastle.
Refer to build.gradle for the libs used in this project.
Many resources exist to understand JWT but I would recommend this short list:
- JWT, JWS and JWE for Not So Dummies!
- JSON Web Token (JWT)
- JSON Web Algorithms (JWA)
- JSON Web Key (JWK)
- CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE)
Even though one can use Google Tink to generate a Ed25519 key pair, I purposely doing to do this with BouncyCastle.
Security.addProvider(new BouncyCastleProvider());
final Ed25519KeyPairGenerator ed25519KeyPairGenerator = new Ed25519KeyPairGenerator();
ed25519KeyPairGenerator.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
final AsymmetricCipherKeyPair asymmetricCipherKeyPair = ed25519KeyPairGenerator.generateKeyPair();
final Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters) asymmetricCipherKeyPair.getPrivate();
final Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters) asymmetricCipherKeyPair.getPublic();
As per rfc8037, next step is to generate a object of type 'OKP'.
final String x = edPublicKey;
final String d = edPrivateKey;
final OctetKeyPair octetKeyPairJWK = new OctetKeyPair.Builder(Curve.Ed25519, new Base64URL(x)).d(new Base64URL(d)).build();
The JSON representation of the octetKeyPairJWK object is:
{"kty":"OKP","d":"o11uN0ai0QZhk2NhrLsaRLtLHAbIyfzwKxyH_XjXO9I=","crv":"Ed25519","x":"SxWU8R32zZliBiC7xOgDFq2AduGgjZ4zKjyAAcbgugI="}
The next step is the creation of JWS on a given payload:
final JWSSigner signer = new Ed25519Signer(octetKeyPairJWK);
final String payload = "Edward, what have you done?";
final JWSObject jwsObject = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.EdDSA).keyID(octetKeyPairJWK.getKeyID()).build(),bnew Payload(payload));
jwsObject.sign(signer);
final String jws = jwsObject.serialize();
Follows the JSON representation of the JWS token:
eyJhbGciOiJFZERTQSJ9.RWR3YXJkLCB3aGF0IGhhdmUgeW91IGRvbmU_.WnfnZYZUxMCkO_9SSIrqD8963WifoT-LtABf2CSVmzgiUwdl-yRloFBb-vFvRSh-MIOINd1EDIVmFDs-rk8JAQ
final JWSVerifier verifier = new Ed25519Verifier(octetKeyPairJWK.toPublicJWK());
assert jwsObject.verify(verifier);
That's it. Enjoy.