Created
April 15, 2019 20:26
-
-
Save bsreera/5e28328b99163af286e8c7ae66c70a79 to your computer and use it in GitHub Desktop.
ECDH JWE AES256GCM P-521
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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