I'm trying to create json web token and getting error like
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:66)
Caused by: java.lang.IllegalArgumentException: RSA signatures be computed using a PrivateKey.Object of class [javax.crypto.spec.SecretKeySpec] must be an instance of interface java.security.PrivateKey
I'm passing base64-encoded PEM file with private key
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXZmSEUrcVM4NlRsYmRFMVR0Mm55V3BPdnFCMjREcWZPc1Q2TFEzMFZFdFBBb0NxCno1T2EvMWwyTFhwZ2tQSG1TNnMxRUVXTUkrZXF3TWFGWHVKVHg1aVhYQk5id1BuSHNTZ2MrUWJnRW5rVzB3M1cKalRYWTF5blU3VmkzYjl2ck9WY2Urb1VkNTZuRXVidnc2ZFYzdXJsbmNMSTJ1a2FWbkVJaVVCRW1DYTMxQXdsUwpOSDRFQWVDUmYzUHhEWW52WnpJZFpBWlliajZsY1VOR1hRNTMyZTRCa1VwbWZwOUl5WDVsNzJ1ZU1RV3k1Z3NvCkR1ZnZYSlM0ZldCRURveFJxaFVNQWFTUHhhTzZQY0VOcDZGK3gxRWhtM0tKVytQU1FLVDJobVl3aUxPeHVrZGMKRHVXd0hNN3Z6YkZYU3lwbUpPWmNpMWw2b3o1T1hZemYvM2JWVHdJREFRQUJBb0lCQUZvbENQa1RTbExxbUN2QQppTUZEb1pnOUIwWmx1NnNVMkp6UFNBZmRDSVp6NE41R0J4VWFCOHRCNlBhNFlFTENQdFVROFA2dGFZb09Nb2ZMCnI1WTE3VXI0eVZGOWkrbVpCS3pudUVCaERqd1o0ZVZVY0xPWTJMbTAwNUswQ1kySExQeHlndDhxdTJac3Rnc1AKRUhMTmwzS1IzY3U2UVNUQ3ozT05kMW0vU3VXekE3UnE3S0hURHZpbnRGRDRRVUY5OXo0UXNycHVoK01lWWJ3ZwprRlhNUGcxWUl2RHJUUGpkNWZNY3EvaGNqR2NDbEVHUWZQL2h6U0M5bGtwcTZKa0lBM1p1Z1U4RDVtaXExWXFWCi9KeU5YZ2lndTd0c3l6UGNYTHM0MG40WkI2NmNCM0JrSDRMajV6YTI1anp4aDVHaldTS0RDb3NxVlowNGR2MHYKNG0wdEh2RUNnWUVBOGtKbzgzUHZkMk1tOXArZlpsZWRFaGdMRnp6cTM4V1dsRlhzV3E1T3gzQ2lkNTNOUWd0UQplVUJXdzRPUzRwOFJieHp1TkRSVDd3enFEWEIzUERIaWZveXVsWlkxcUhtcUxRY3VBelVHTmk4S2JkdHp2Q2hJCkNFVXdCMDhOeTMrMDdzOTRycGZHcUZ2cGFhb1RSRWluNWJZVWtKVkVHdW9rRW9oVHNQN1RpZVVDZ1lFQXhaS0oKMXJOM2hJRWRtditkODBJUFZ2Y2FVR05vSUxWd1hrZThIOUtlYUlEV1dqa2RFb2NtY09ZWDZJSnVINURjVGtCKwpzQlpwVUJmVzhiS3B0eFowM2hDWmhhZW03SUo5WGFrU2tiNDJhV1FQNWhmWXhFaktSYTcrN1I1VXM3ajMxNUxHCjVwTWNDQ01ybEpnTzRSZm9RUGIxMjNkbG43TEVLS0p2TVhUelh5TUNnWUVBeE56Q2ZGTlIzU3B0bHl2UFZGTU8KQ0k0Uk5Ta0RsQ1AwWVVZUmN2OENkWDlLQnZuc3VpYUhsb0I2QVJjQ1hiWDFiTjJObEU2UmhraHdTY3VDbVIvUQpkaFhNS1RLUEdBRUdFT0VzdXQ1ejFjUVVMWUdQWXU4NDJiK2ZiOUVGM01CQ1AyM0pHOWVxVDFXaEw0Uk5jOGUyCjZDdzJPZWVTR0d6OE16TWxEMGVFanlFQ2dZRUFwV3ZFTFJlbWdqTDQ3c1lISVoyMTZrS0tyYlFOZ3hWbk9Ba24KNGgwZXRMRHF5Qy81djRHWkZmNFJGb1BlWUYrUmxaTTZmNFRFT0dNOWZMRHltSEVjK0xFOVdVSzk2Rmg1VHVvNAp1ZjVnNEd6L1FzL0VsdE83U0F6MU5PT29WN0lQRVZlN1lXTGFuWldVNzUxQkdBWkVWK0J1aVlxMmM3Zmh0WVFMClJZVitIN0VDZ1lFQXZLTGhndkN5M3pHMWV0SStLT1p3ajRrUkxkSU5QQ0x0N2dHT1lGdnphRkdFMXYrZFBuUUkKYTEwWEJ5UmhqMWxwbUZxaFp6aHlIUldmVVpOc1lyN014T2E2NXZkd3lHWTZ2QzJpZWU2T04vUVhPajlmdzQ2eApxaUxoajNPTnNiaTJKQlovV0FSc09YQ09KZXVWTmNuZ29kdnBkeDd5UTJMZlVWcTl0ZTVHREswPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
Below the code
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcGdJQkFBS0NBUUVBMFZTLytaaDd0SWdtYVRKc0ZSMnJmNHVDanVOVEY0eWcwaXFSZ0dScmZsTEFtdkRUCkpSUm5JdmMvZkFBSFkyOEwrSk1RdHFvdE9wU1dnZ2hCSXZTaUw0bktleFQ2MHk4Y0VWU09zRmN0bGVVVkZxN3IKclRZREd3TGxFRzZrNDU5TmppMDh2dnVjdGkzbHRjSHo1b3ZzMUxGbXRkeUhITTdTczhEKzA5eEszZmkrU1ZUWApHQS9OMml2UEhGaHRwQlVCZnJNUWZUNm1Zckg5VXZsZFdlSlBZWENDYnI1TGwwc2IzaTdDV2FEc1I2NFlqTXlTClRid0U1ZVloWngwamJJTnNDQitRK0JqaDFZcklKMlV1T2xIZ2ozemJvVENnZ2pDWGsxbGdUaHJWdjJjenBTMmUKN0tFWmkrK3dwSmtvdHNUcTF4Q3RLU0wrMmg1NTFKbDRoOHJHQ3dJREFRQUJBb0lCQVFDKzZTWTBnb2EvdlRRYQoyT3VOem9Oc1RWWUM3dndIRERCWHZJNzZvNXNObUhja1YrS1pmS1FiVlpkR2hkZzNMVDJqdEt5WGkxaTRobTlGCnBEV1RwYnlNMG9RaUFKNUpJRHZlNmxsQUppSGpCUXhZcGFzM1MzMUZrenhKNGo3cmdZdi8wTzRIMS8yeWdPVngKQUxScVhNN2ZvL05paFArTW5HdTVtSmhQckNkempCSHVsS2IySUhQMEF5YXc1NFg3d0pHeVlIOXdQY2FOV2ZZdwowQjlocnFRK2VLSDBUS2dpcGRTdmVFbTR3SEVDUmxhUU95amc2ejIwQ3dsa3R2anRnc2JzVzFLZDVyc1Znb0tyClY4NjZreTltbFpoSkZoRHZrUHlOVUlXaW9QT3lGWDd1SHlQN1RzdGNRampYN3BqYlZYZTJ4U1pMU0toVFQxcnEKRzR6TzJyUUJBb0dCQVA4cG5Wblk0TVN6WUw3LzZRbmJYOERtZCt4eXlXd293VFd0d1F4TjZKNnV6ZzEzNHp3cApUdmlsak9BMlpwdy9iZ0UrY3VGa2piTXJQcFJoZVgrTFNpL1JBTGlHem1vNk5rNDFmd0J3OGRWOWs1TmFWWDRaCjN3UkdOR24rS1BWb2psbG9pMmQ2WWl0Q09nY1V4RVBVZDZaVUVoN2VlVjUybEpIVUlnZDBtR2NMQW9HQkFOSUUKb01ZU3M3NFZqYWhaUy8yVmlqZmV4L3BjL3cveWpFSUFVZUxDRjQrUEg4TFJkalY1bDV1YytPa1k4cHN5Z3BQNwo5azAxZUlJWXhzS0UwZEEzV1YrbUVZZU1CU2R6dXZZVDhwZEhBY291cFlESTdvbGtQZEpBdWpjTTY2eExtbWpKCnd0R3BQdkh3OEsvbWNDQjRkeVNrLzVSSERWc0ZKa0ZLRUt0ZjVuMEJBb0dCQUpwNm1rM3o5SmlCdFBmTnZVdC8KYWVoQ1g2WmlGRG9NTG5VT0hjc1NPOXdlSHBlZTFvN3N2MmZmNm5zdjFFMlNSVW94Z2FHZG5BQTJGU3dHRzJXeApjWmVqWkZsVEhCTEo3V2pLRUhxMjVtS0hKVnBYblZ5NzB2NG1kc01ZNGJrNXRMekNnMnVCZDMrVEY4aUR0Uk1QCnhlU0lEM1JxNG5Yak9xMVREY3NQdHRqakFvR0JBTE5vY3JOaUxKdjRLNUFoNEZHYlduekoyb21jd2VNc3J2WisKOFhURm0zenVwaEkxLzBaRlBlY1lYR1k4QXB2anRUcVhwbHRranpLTDJkYzN3VWllejhGdXkxREFvM0tGWWJSdgphL0FoSDMxSkJlY1RQdnF0WUVacE51cHFKaldFVEQ2eUJMUTRZV1lyRG1FbGVLbTBYd3MxeklNdGcxSTYvdWdOClRsb256VzBCQW9HQkFLS1FzNmluczJBbVl3UEtvVGJEOUlza3NtdElZOUNacG1pTVVCRkZBMld6dFBSNUVhUzAKYTgrb2JaRXNRa3dZZzVSQTZUS0FzZUlJem1yZUE3RkVUd21nMmNmZW1wOW81bXJETy85bkk4blFYU24xeEdZWApmN2VBMlh6bHcvN3lrMENaekYwMnA4b3dSMzc3cFcrWkp4RkgraHJPUnh4dWFWcnJob3I5VVN4TwotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=");
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId("ID")
.setIssuedAt(now)
.setSubject("subject")
.setIssuer("issuer")
.signWith(signatureAlgorithm, signingKey);
//Builds the JWT and serializes it to a compact, URL-safe string
System.out.println("-------------------------------------"+builder.compact());
You've used the wrong key SecretKeySpec. It should be PrivateKey.
For example:
Jwts.builder().signWith(SignatureAlgorithm.RS256, getPrivateKey("RSA",keyContent))
.setAudience("audien")
.setIssuer("issuer")
.setSubject("subject")
.setExpiration(expiredDate).compact();
As requested, I've added the loadPrivateKey function here.
public static PrivateKey getPrivateKey(String algorithm, String keyContent)
throws Exception{
try {
byte[] encoded = decodeBase64(keyContent);
KeyFactory kf = KeyFactory.getInstance(algorithm);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
PrivateKey privateKey = kf.generatePrivate(keySpec);
return privateKey;
} catch (Exception ex) {
//log error
throw ex;
}
}
Related
I need some help with JWS Signing with RSA 256 privatekey -RSASSA-PKCS1-v1.5 SHA-256
I m working on SAP PI/PO.
I am unable to retrieve the RSA privatekey saved in server's OS folder, so I am trying to pass the pem(base64 encoded) key as a string.
My requirement is to generate Header & payload & signed it.
Sample input Header:
{"alg": "RS256","kid": "asff1233dd"}
sample Json Payload:
{"CompInvoiceId": "0009699521","IssueDtm": "20220623"}<br />
Error: I am able to generate Header.payload in base64 url encode but the signature part is getting corrupted when I convert the privatekey to PKCS8encoding.
The generated JWS looks like:
eyJhbGciOiJSUzI1NiIsImtpZCI6Imh5d3kzaHIifQ.eyJDb21waW52b2ljZSI6IjAwOTk5MzMzIiwic3VibWl0SWQiOiIxMjM0NSJ9.[B#42ace6ba
This is signature part which is getting corrupted - [B#42ace6ba
Kindly help with below code:
This is because of this declaration byte[] signed = null, when I remove
that it just throwserror as cannot find variable for signed.
Please help me with passing privatekey & signature.
The Java code I am working on:
I am passing :
Json data= data,
header = header
Privatekey in base64 = key
String jwsToken(String key, String data, String header, Container container) throws
StreamTransformationException{
String tok = null;
byte[] signed = null;
try {
StringBuffer token = new StringBuffer();
//Encode the JWT Header and add it to our string to sign
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes("UTF-
8")));
token.append(".");
//Encode the Json payload
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(data.getBytes("UTF-8")));
//Separate with a period
token.append(".");
//String signedPayload =
Base64.getUrlEncoder().withoutPadding().encodeToString(signature.sign());
PrivateKey privatekey = null;
String privateKeyPEM = key;
//String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
byte[] decodePrivateKey = Base64.getDecoder().decode(key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodePrivateKey);
privatekey = (PrivateKey) keyFactory.generatePrivate(keySpec);
Signature sig = Signature.getInstance( "SHA256withRSA" );
sig.initSign( ( PrivateKey ) privatekey );
sig.update(token.toString().getBytes("UTF-8"));
signed=sig.sign();
tok = (token.toString());
}
catch (Exception e) {
e.printStackTrace();
}
return tok;
}
Instead of appending byte array, encode it in base64 then append it
signed = sig.sign();
token.append(Base64.getUrlEncoder().withoutPadding().encodeToString(signed));
Now I want to generate an JWT token to request apple server follow this docs, I have the p8 file download from apple, how to get jwt sign key from p8 file? this is my jwt token generate code:
Map<String,Object> jwtHeader = new HashMap<>();
jwtHeader.put("alg","ES256");
jwtHeader.put("kid","YDKL424AF9");
jwtHeader.put("typ","JWT");
Map<String,Object> appleJwtPayload = new HashMap<>();
appleJwtPayload.put("iss","5fb8e836-27d7-4390-8f40-008acd64a29d");
appleJwtPayload.put("iat",System.currentTimeMillis() / 1000L);
appleJwtPayload.put("exp",System.currentTimeMillis() / 1000L + 60 * 15);
appleJwtPayload.put("aud","appstoreconnect-v1");
appleJwtPayload.put("nonce",UUID.randomUUID().toString());
appleJwtPayload.put("bid","com.earth.dolphin");
String appleKey = "<how to get the apple key>";
SecretKey secretKey = new SecretKeySpec(appleKey.getBytes(), SignatureAlgorithm.ES256.getJcaName());
String accessToken = Jwts.builder()
.setClaims(appleJwtPayload)
.setHeader(jwtHeader)
.signWith(secretKey)
.compact();
I read the KeyStore code follow this question, but I still could not figure out how to do it, any one could help me?
get the sign key like this:
byte[] p8der = Files.readAllBytes(Path.of("/opt/apps/dolphin-post/AuthKey_YDKL424AF9.p8"));
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(new org.apache.commons.codec.binary.Base64().decode(p8der));
PrivateKey appleKey = KeyFactory.getInstance("EC").generatePrivate(priPKCS8);
the file AuthKey_YDKL424AF9.p8 was download from apple, you should remove the begin and end header of the file. This is my full function to get private key:
public static PrivateKey getPrivateKey(String filename, String algorithm) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Java did not support the algorithm:" + algorithm, e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("Invalid key format");
}
}
you can use it like this:
PrivateKey appleKey = SecurityUtil.getPrivateKey(APPLE_PRIVATE_KEY_PATH,"EC");
the APPLE_PRIVATE_KEY_PATH in my OS is:
apple.private.key.path=/opt/apps/dolphin-post/AuthKey.p8
changed it to your path.
We need to handle requests from an API gateway. The identity of the user will be passed to us through and encrypted (by private key) JWT token and we received the public key (in Base64) to validate it.
For now I've been failing to do that.
What I did manage to do is to encrypt and then again validate my own token using a self generated private/public key:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
kp = kpg.generateKeyPair();
//generate & sign simple token:
Map<String, Object> claims = new HashMap<>();
claims.put("id", "xxx");
claims.put("role", "user");
token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.RS256, kp.getPrivate()).compact();
//now sign the thing
Claims claims = Jwts.parser().setSigningKey(kp.getPublicKey()).parseClaimsJws(base64EncodedToken).getBody();
System.out.println(claims.get("id")); //gives me xxx as expected
No issue here.
Next step was to externalise (file) those generated keys; e.g.:
out = new FileWriter("key.pub");
out.write(encoder.encodeToString(kp.getPublic().getEncoded()));
out.close();
And then instead of using a KeyPairGenerator create the Public/Private keys by reading them from the (Base64) file and decoding them:
public PrivateKey getPrivateKey() throws Exception {
String base64PrivateKey = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("private.key").toURI())));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec (Base64.getDecoder().decode(base64PrivateKey.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
public PublicKey getPublicKey() throws Exception {
String base64PublicKey = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("public.key").toURI())));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(base64PublicKey.getBytes()));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
When I then run the same process again (generate encrypted token & validate it):
Exception in thread "main" io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
I must be missing something since I have little experience with encryption.
P.S. The files are 1 liners likes this:
public.key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxetc3258...
private.key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEA...
I have a PrivateKey and a PublicKey and use the privateKey to init Signature and publicKey to verify the Signature:
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// decode public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(pubKeyBytes);
RSAPublicKey pubKey = (RSAPublicKey)
keyFactory.generatePublic(publicSpec);
//decode private key
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(prvKeyBytes);
RSAPrivateKey privKey = (RSAPrivateKey)
keyFactory.generatePrivate(privSpec);
//header and body Base64 decoded value
String headerString = mapper.writeValueAsString(header);
String headerEncoded =
Base64.getUrlEncoder().encodeToString(headerString.getBytes());
String payloadString = mapper.writeValueAsString(payload);
String payloadEncoded =
Base64.getUrlEncoder().encodeToString(payloadString.getBytes());
String tempAccessToken = hearderEncoded+"."+payloadString;
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privKey);
sign.update(tempAccessToken.getBytes("UTF-8"));
byte[] signatureBytes = sign.sign();
sign.initVerify(pubKey);
sign.update(tempAccessToken.getBytes("UTF-8"));
String jsonToken = Base64.getUrlEncoder().encodeToString(signatureBytes);
String JWTtoken = tempAccessToken + "." + jsonToken;
finally I get the JWT token below (dummy value):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4MzliN2NhNC02MDE1LTQ0OWQtOGZiNi02jkyYzk1Ny1jYTNjLTQyMWQtOTk2zY2VkNTAzZGViNWYiLCJleHAiOjE1MzIwMDQwMTcsImF1ZCI6ImFjY291bnQtZC5kb2N1c2lnbi5jb20iLzY29wZSI6InNpZ25hdHVyZSBpbXBlcnNvbmF0aW9uIn0=.YNZzR0HgPWFm4dXMMHn3czEDRukYUB0Hyw7YP_BGY2dniIMqpH4Ctz5EEHcHrNT_mGImcp026w-isYgv56TTugYnkcAs8HH0YXa1Ey0skdjVYoZHdeyPC8Ci9xeOQF9wf4VjrBboaRxWkVXfngOHHewpV42NcaXxwmGlresWukHVmmjbFokd1Cm5BJKVhVlsZWuftcJlC3XoO9REjaZX78YTY9S5bpXmsZBYr20wHsWJrkP9EWGf7WSGHVXGBJfCpvOTZDC8_4B12ToD_RKjk6n5s8-F7X54KY4kx6Gg7xnk55vDw==
I'm not able to get the accessToken using this JWT Token. I will get the response instead:
"error" :"invalid_request";
NOTE: I am using this JWT token to get the access token for DocuSign Application.
I am looking to develop a JWT app with RSA encryption using "Nimbus JOSE+JWT" library. I am seeking sample code.
I would like to use the following Maven dependency:
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>3.10</version>
</dependency>
Note: Please always use the latest version from Maven Central repository.
If you're using the latest version of 4.23 of 'Nimbus Jose JWT' then there is some minor changes in the API.
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>4.23</version>
</dependency>
I've shown the code below for reference:
public class JwtJoseExample {
public static void main(String[] args) {
KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
// generate the key pair
KeyPair keyPair = keyPairGenerator.genKeyPair();
// create KeyFactory and RSA Keys Specs
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(keyPair.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(keyPair.getPrivate(), RSAPrivateKeySpec.class);
// generate (and retrieve) RSA Keys from the KeyFactory using Keys Specs
RSAPublicKey publicRsaKey = (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
RSAPrivateKey privateRsaKey = (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
JWTClaimsSet.Builder claimsSet = new JWTClaimsSet.Builder();
claimsSet.issuer("https://my-auth-server.com");
claimsSet.subject("John Kerr");
claimsSet.audience(getAudience());
claimsSet.expirationTime(new Date(new Date().getTime() + 1000*60*10));
claimsSet.notBeforeTime(new Date());
claimsSet.jwtID(UUID.randomUUID().toString());
System.out.println("--------------------------");
System.out.println("Claim Set : \n"+claimsSet.build());
// create the JWT header and specify:
// RSA-OAEP as the encryption algorithm
// 128-bit AES/GCM as the encryption method
JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP, EncryptionMethod.A128GCM);
// create the EncryptedJWT object
EncryptedJWT jwt = new EncryptedJWT(header, claimsSet.build());
// create an RSA encrypter with the specified public RSA key
RSAEncrypter encrypter = new RSAEncrypter(publicRsaKey);
// do the actual encryption
jwt.encrypt(encrypter);
// serialize to JWT compact form
String jwtString = jwt.serialize();
System.out.println("\nJwt Compact Form : "+jwtString);
// in order to read back the data from the token using your private RSA key:
// parse the JWT text string using EncryptedJWT object
jwt = EncryptedJWT.parse(jwtString);
// create a decrypter with the specified private RSA key
RSADecrypter decrypter = new RSADecrypter(privateRsaKey);
// do the decryption
jwt.decrypt(decrypter);
// print out the claims
System.out.println("===========================================================");
System.out.println("Issuer: [ " + jwt.getJWTClaimsSet().getIssuer() + "]");
System.out.println("Subject: [" + jwt.getJWTClaimsSet().getSubject()+ "]");
System.out.println("Audience size: [" + jwt.getJWTClaimsSet().getAudience().size()+ "]");
System.out.println("Expiration Time: [" + jwt.getJWTClaimsSet().getExpirationTime()+ "]");
System.out.println("Not Before Time: [" + jwt.getJWTClaimsSet().getNotBeforeTime()+ "]");
System.out.println("Issue At: [" + jwt.getJWTClaimsSet().getIssueTime()+ "]");
System.out.println("JWT ID: [" + jwt.getJWTClaimsSet().getJWTID()+ "]");
System.out.println("===========================================================");
} catch (NoSuchAlgorithmException | InvalidKeySpecException | JOSEException | ParseException e) {
System.out.println(e.getMessage());
}
}
private static List<String> getAudience(){
List<String> audience = new ArrayList<>();
audience.add("https://my-web-app.com");
audience.add("https://your-web-app.com");
return audience;
}
}
The output is:
Claim Set :
{"sub":"John Kerr","aud":["https:\/\/my-web-app.com","https:\/\/your-web-app.com"],"nbf":1471116052,"iss":"https:\/\/my-auth-server.com","exp":1471116652,"jti":"8769fc6d-b69f-45e3-b1a5-52695c23675e"}
Jwt Compact Form :
eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.f2ZZyMaJi03RqunyWsLvIr7tNX1KvTRUcpN9qsBHvbXIouZCyepQMsbI1v88GHuLIV3f6SviCDyICp7kZCj_9q-yIi_dIuroADWQ-P_UnqNPRXQ1yEwbmrLUK80lBtKyc3Z6g_3Db_HLtD6QPEq-zUAh3wJ7uSPxhql2oc9otGc.Xbyrf4iWM0shNp4S.TCKoJGAEQ4rpJJk2qZP11awxTEWTg-r5VpppGgZNhiHCBhnGnyR2sb86O7ISc3j-i4OYp7Xl2vThzztD1ojy_IKPYQkg_iACuo6yjzdopQQT143vjYuFLfFhQFfjfCoO6iibTqK7vmqfF0bUWD6Nj-4MwjlW6dFV7mNQEN50dkiMrFMZkmiVKZRa50jOK1NcoWYiKSrCOQduJYibJfF6jSQARX9MsX5tib-3BXSsKtPLNrQ6mFfvDzzruBuO4gKWLE3PQPUfIQ.gXt5KcpxEbfYLP854GvcQw
===========================================================
Issuer: [ https://my-auth-server.com]
Subject: [John Kerr]
Audience size: [2]
Expiration Time: [Sun Aug 14 01:00:52 IST 2016]
Not Before Time: [Sun Aug 14 00:50:52 IST 2016]
Issue At: [null]
JWT ID: [8769fc6d-b69f-45e3-b1a5-52695c23675e]
===========================================================
//This is a complete encryption and decryption module using
//Algorithm: JWEAlgorithm.RSA_OAEP_256
//Encryption Method: A128CBC_HS256
public static String encrypt(String text) throws Exception {
// Set the plain text
Payload payload = new Payload(text);
// Create the header
JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128CBC_HS256);
// Create the JWE object and encrypt it
JWEObject jweObject = new JWEObject(header, payload);
jweObject.encrypt(new RSAEncrypter(getPublicKey()));
// Serialise to compact JOSE form...
String jweString = jweObject.serialize();
LOG.info("Generated Encrypted Key : {}", jweString);
return jweString;
}
public static String decrypt(String text) throws Exception {
// Parse into JWE object...
JWEObject jweObject = JWEObject.parse(text);
jweObject.decrypt(new RSADecrypter(getPrivateKey()));
// Get the plain text
Payload payload = jweObject.getPayload();
System.out.println(payload.toString());
return payload.toString();
}
private static RSAPublicKey getPublicKey() throws Exception {
String filename = "/home/vaibhav/Setups/cert/pub.der";
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int)f.length()];
dis.readFully(keyBytes);
dis.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return (RSAPublicKey) kf.generatePublic(spec);
}
private static RSAPrivateKey getPrivateKey() throws Exception {
String filename = "/home/vaibhav/Setups/cert/private.pkcs8";
File f = new File(filename);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int)f.length()];
dis.readFully(keyBytes);
dis.close();
PKCS8EncodedKeySpec spec1 = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return (RSAPrivateKey) kf.generatePrivate(spec1);
}
I implemented the code to use "nimbus-jose-jwt" library, please find the code below
JWTClaimsSet jwtClaims = new JWTClaimsSet();
jwtClaims.setIssuer(ISSUER);
jwtClaims.setSubject(SUBJECT);
List<String> aud = new ArrayList<String>();
aud.add("https://app-one.com");
aud.add("https://app-two.com");
jwtClaims.setAudience(aud);
// Set expiration in 10 minutes
jwtClaims.setExpirationTime(new Date(new Date().getTime() + 1000*60*10));
jwtClaims.setNotBeforeTime(new Date());
jwtClaims.setIssueTime(new Date());
jwtClaims.setJWTID(UUID.randomUUID().toString());
System.out.println("=========== JWT CLAMINS =============");
System.out.println(jwtClaims.toJSONObject());
// Request JWT encrypted with RSA-OAEP and 128-bit AES/GCM
JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP, EncryptionMethod.A128GCM);
// Create the encrypted JWT object
EncryptedJWT jwt = new EncryptedJWT(header, jwtClaims);
// Create an encrypter with the specified public RSA key
RSAEncrypter encrypter = new RSAEncrypter(publicKey);
jwt.encrypt(encrypter);
String jwtString = jwt.serialize();
System.out.println(jwtString);
// Parse back
jwt = EncryptedJWT.parse(jwtString);
// Create a decrypter with the specified private RSA key
RSADecrypter decrypter = new RSADecrypter(privateKey);
// Decrypt
jwt.decrypt(decrypter);
// Retrieve JWT claims
System.out.println(jwt.getJWTClaimsSet().getIssuer());;
System.out.println(jwt.getJWTClaimsSet().getSubject());
System.out.println(jwt.getJWTClaimsSet().getAudience().size());
System.out.println(jwt.getJWTClaimsSet().getExpirationTime());
System.out.println(jwt.getJWTClaimsSet().getNotBeforeTime());
System.out.println(jwt.getJWTClaimsSet().getIssueTime());
System.out.println(jwt.getJWTClaimsSet().getJWTID());
This code has also use the public and private keys to create JWT token, also you will need those keys to extract claims and validate it.
Once you run this code, you should be able to see following jwtClaims:
{
"exp": 1429126207,
"sub": "alice",
"nbf": 1429125607,
"aud": [
"https://app-one.com",
"https://app-two.com"
],
"iss": "A FaceBook Cooperation",
"jti": "5c94d2db-e818-4746-b2f2-a4cd084d5a44",
"iat": 1429125607
}