Skip to content

Instantly share code, notes, and snippets.

@bsreera
Created April 15, 2019 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bsreera/5e28328b99163af286e8c7ae66c70a79 to your computer and use it in GitHub Desktop.
Save bsreera/5e28328b99163af286e8c7ae66c70a79 to your computer and use it in GitHub Desktop.
ECDH JWE AES256GCM P-521
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.ECDHDecrypter;
import com.nimbusds.jose.crypto.ECDHEncrypter;
import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.EncryptedJWT;
import net.minidev.json.JSONObject;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.text.ParseException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class ECDH_JWE {
static String x = "AcA5yijXdEHu04aYoYkTJNgPpey1sctD5fxBNTdosfKKHOi4Jw14vYK3O8bwG2bBV3VL3d98y88Y7BcEy4UOkqG1";
static String y = "AKDTM7BHYkugTIzJnRkIw1kQoCXU7-XBSKGwAHoWxad9XSz7GtUQZnlxuAusuz_n_llPHnZWLKLhLh5uoyvcWEVj";
static String d = "AOQxfGRdjz66zngO7OAKkHTpGUOPvra6_QRGBXdiRogco7fX4eTJpgPjxnNeguHlUtdWIqkbDFiPCJDOqfk7ozMO";
static ECKey serverJWK = new ECKey.Builder(Curve.P_521, new Base64URL(x), new Base64URL(y))
.d(new Base64URL(d))
.build();
static ECKey clientKeyJWK = generateEpemeralECKeyJwk();
public static void main(String[] args) throws Exception {
System.out.println("**************** Client Public Key Header: START ********************\n");
// To be passed in the Client-Public-Key header to get encrypted response.
System.out.println(Base64.getEncoder().encodeToString(clientKeyJWK.toPublicJWK().toString().getBytes("UTF-8")));
System.out.println("**************** Client Public Key Header: END ********************\n");
// Client sends encrypted request, Server decrypts
requestDecryption();
// Server sends encrypted response, Client decrypts
responseEncryption();
}
private static void requestDecryption() throws JOSEException, ParseException {
System.out.println("**************** Client Encryption: START ********************\n");
Map<String, String> vcnReguest = new HashMap<>();
vcnReguest.put("Client", "Encrypted Request from Client");
JSONObject vcnRequest = new JSONObject(vcnRequest);
// Uses server Public Key, Jose library generates the ephemeral Key Pair,
// Public Key is added in the JWE header, Private Key is discarded
String vcnRequestJWE = encryptJWE(serverJWK, vcnRequest);
System.out.println(vcnRequestJWE);
System.out.println("\n**************** Client Encryption: END ********************\n\n");
System.out.println("\n\n**************** Server Decryption: START ********************\n");
// Uses Server Private Key, Client Public Key in the header
String vcnRequestDecrypted = decryptJWE(vcnRequestJWE, serverJWK);
System.out.println(vcnRequestDecrypted);
System.out.println("\n**************** Server Decryption: END ********************\n\n");
}
private static void responseEncryption() throws JOSEException, ParseException {
System.out.println("**************** Server Encryption: START ********************\n");
Map<String, String> vcnReguest = new HashMap<>();
vcnReguest.put("Server", "Encrypted Response from Server");
JSONObject vcnResponse = new JSONObject(vcnReguest);
// Uses client Public Key(from the Client-Public-Key header), server Private Key
String vcnResponseJWE = encryptJWE(clientKeyJWK, vcnResponse);
System.out.println(vcnResponseJWE);
System.out.println("\n**************** Server Encryption: END ********************\n\n");
System.out.println("\n\n**************** Client Decryption: START ********************\n");
// Uses client Private Key, server Public Key in JWE header
String vcnResponseDecrypted = decryptJWE(vcnResponseJWE, clientKeyJWK);
System.out.println(vcnResponseDecrypted);
System.out.println("\n**************** Client Decryption: END ********************");
}
private static String decryptJWE(String vcnRequestJWE, ECKey ecPrivateKeyJWK) throws ParseException, JOSEException {
// Parse JWE & validate headers
JWEObject jweObjectServer = EncryptedJWT.parse(vcnRequestJWE);
// Set PrivateKey and Decrypt
ECDHDecrypter decrypter = new ECDHDecrypter(ecPrivateKeyJWK.toECPrivateKey());
decrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
jweObjectServer.decrypt(decrypter);
return jweObjectServer.getPayload().toString();
}
private static String encryptJWE(ECKey ecPublicKeyJWK, JSONObject payload) throws JOSEException {
// Build JWE header
JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A256GCM)
.build();
// Build JWE Object
JWEObject jweObjectClient = new JWEObject(header, new Payload(payload));
// Set Public Key, Encrypt
ECDHEncrypter encrypter = new ECDHEncrypter(ecPublicKeyJWK.toECPublicKey());
encrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
jweObjectClient.encrypt(encrypter);
return jweObjectClient.serialize();
}
public static ECKey generateEpemeralECKeyJwk() {
try {
// Generate EC key pair with P-521 curve
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
gen.initialize(Curve.P_521.toECParameterSpec());
KeyPair keyPair = gen.generateKeyPair();
// Convert to JWK format
return new ECKey.Builder(Curve.P_521, (ECPublicKey) keyPair.getPublic())
.privateKey((ECPrivateKey) keyPair.getPrivate())
.build();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment