From ade641922c5d199d1beb608b8266ead952294e26 Mon Sep 17 00:00:00 2001 From: MaxKey Date: Mon, 14 Feb 2022 09:47:01 +0800 Subject: [PATCH] Jwt Service optimize --- ...aultJwtEncryptionAndDecryptionService.java | 37 ++++++++++++-- ...DefaultJwtSigningAndValidationService.java | 37 +++++++++++++- .../jwt/endpoint/adapter/JwtAdapter.java | 48 ++++++++----------- .../endpoint/AuthorizationEndpoint.java | 2 +- .../endpoint/UserInfoOIDCEndpoint.java | 34 +++++-------- .../oidc/idtoken/OIDCIdTokenEnhancer.java | 47 ++++++++---------- 6 files changed, 123 insertions(+), 82 deletions(-) diff --git a/maxkey-common/src/main/java/org/maxkey/crypto/jwt/encryption/service/impl/DefaultJwtEncryptionAndDecryptionService.java b/maxkey-common/src/main/java/org/maxkey/crypto/jwt/encryption/service/impl/DefaultJwtEncryptionAndDecryptionService.java index f47236fee..bb887d1af 100644 --- a/maxkey-common/src/main/java/org/maxkey/crypto/jwt/encryption/service/impl/DefaultJwtEncryptionAndDecryptionService.java +++ b/maxkey-common/src/main/java/org/maxkey/crypto/jwt/encryption/service/impl/DefaultJwtEncryptionAndDecryptionService.java @@ -52,7 +52,7 @@ import com.nimbusds.jose.jwk.RSAKey; */ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAndDecryptionService { - private static Logger logger = LoggerFactory.getLogger(DefaultJwtEncryptionAndDecryptionService.class); + private static Logger _logger = LoggerFactory.getLogger(DefaultJwtEncryptionAndDecryptionService.class); // map of identifier to encrypter private Map encrypters = new HashMap(); @@ -106,6 +106,25 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn buildEncryptersAndDecrypters(); } + + public DefaultJwtEncryptionAndDecryptionService(String jwkSetString, String defaultEncryptionKeyId,String defaultAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException { + JWKSetKeyStore keyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}"); + this.defaultEncryptionKeyId = defaultEncryptionKeyId; + this.defaultAlgorithm = JWEAlgorithm.parse(defaultAlgorithm); + _logger.trace(" encryptAlgorithm {}" , defaultAlgorithm); + + // convert all keys in the keystore to a map based on key id + for (JWK key : keyStore.getKeys()) { + if (!Strings.isNullOrEmpty(key.getKeyID())) { + this.keys.put(key.getKeyID(), key); + } else { + throw new IllegalArgumentException("Tried to load a key from a keystore without a 'kid' field: " + key); + } + } + + buildEncryptersAndDecrypters(); + + } @PostConstruct @@ -158,6 +177,14 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn public JWEAlgorithm getDefaultAlgorithm() { return defaultAlgorithm; } + + public JWEAlgorithm getDefaultAlgorithm(String algorithm) { + if(algorithm.startsWith("RSA")) { + return defaultAlgorithm; + }else { + return JWEAlgorithm.DIR; + } + } public void setDefaultAlgorithm(String algorithm) { defaultAlgorithm = JWEAlgorithm.parse(algorithm); @@ -182,7 +209,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn jwt.encrypt(encrypter); } catch (JOSEException e) { - logger.error("Failed to encrypt JWT, error was: ", e); + _logger.error("Failed to encrypt JWT, error was: ", e); } } @@ -202,7 +229,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn jwt.decrypt(decrypter); } catch (JOSEException e) { - logger.error("Failed to decrypt JWT, error was: ", e); + _logger.error("Failed to decrypt JWT, error was: ", e); } } @@ -231,7 +258,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn RSADecrypter decrypter = new RSADecrypter(((RSAKey) jwk).toRSAPrivateKey()); decrypters.put(id, decrypter); } else { - logger.warn("No private key for key #" + jwk.getKeyID()); + _logger.warn("No private key for key #" + jwk.getKeyID()); } // add support for EC keys @@ -246,7 +273,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn decrypters.put(id, decrypter); } else { - logger.warn("Unknown key type: " + jwk); + _logger.warn("Unknown key type: " + jwk); } } diff --git a/maxkey-common/src/main/java/org/maxkey/crypto/jwt/signer/service/impl/DefaultJwtSigningAndValidationService.java b/maxkey-common/src/main/java/org/maxkey/crypto/jwt/signer/service/impl/DefaultJwtSigningAndValidationService.java index f77b0b67a..7c7c4e41f 100644 --- a/maxkey-common/src/main/java/org/maxkey/crypto/jwt/signer/service/impl/DefaultJwtSigningAndValidationService.java +++ b/maxkey-common/src/main/java/org/maxkey/crypto/jwt/signer/service/impl/DefaultJwtSigningAndValidationService.java @@ -46,7 +46,8 @@ import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jwt.SignedJWT; public class DefaultJwtSigningAndValidationService implements JwtSigningAndValidationService { - + final static Logger _logger = LoggerFactory.getLogger(DefaultJwtSigningAndValidationService.class); + // map of identifier to signer private Map signers = new HashMap(); @@ -111,7 +112,39 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid buildSignersAndVerifiers(); } - + /** + * Build this service based on the given keystore. All keys must have a key + * id ({@code kid}) field in order to be used. + * see DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) + * @param jwkSetString + * @param defaultSignerKeyId + * @param defaultAlgorithm + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + * @throws JOSEException + */ + public DefaultJwtSigningAndValidationService(String jwkSetString, String defaultSignerKeyId,String defaultAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException { + JWKSetKeyStore keyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}"); + this.defaultSignerKeyId = defaultSignerKeyId; + this.defaultAlgorithm = JWSAlgorithm.parse(defaultAlgorithm); + _logger.trace(" signingAlg {}" , defaultAlgorithm); + + // convert all keys in the keystore to a map based on key id + if (keyStore!= null && keyStore.getJwkSet() != null) { + for (JWK key : keyStore.getKeys()) { + if (!Strings.isNullOrEmpty(key.getKeyID())) { + // use the key ID that's built into the key itself + // (#641): deal with JWK thumbprints + this.keys.put(key.getKeyID(), key); + } else { + // create a random key id + String fakeKid = UUID.randomUUID().toString(); + this.keys.put(fakeKid, key); + } + } + } + buildSignersAndVerifiers(); + } /** * @return the defaultSignerKeyId */ diff --git a/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java index bf09e3fe7..299c1e0b3 100644 --- a/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java @@ -25,7 +25,6 @@ import java.util.UUID; import org.joda.time.DateTime; import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter; -import org.maxkey.crypto.jose.keystore.JWKSetKeyStore; import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService; import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService; import org.maxkey.entity.apps.AppsJwtDetails; @@ -34,12 +33,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.ModelAndView; -import com.nimbusds.jose.EncryptionMethod; import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWEHeader; import com.nimbusds.jose.JWEObject; -import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.Payload; import com.nimbusds.jwt.JWT; @@ -101,15 +97,18 @@ public class JwtAdapter extends AbstractAuthorizeAdapter { @Override public Object sign(Object data,String signatureKey,String signature) { if(!jwtDetails.getSignature().equalsIgnoreCase("none")) { - JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+jwtDetails.getSignatureKey()+"]}"); try { DefaultJwtSigningAndValidationService jwtSignerService = - new DefaultJwtSigningAndValidationService(jwkSetKeyStore); - jwtSignerService.setDefaultSignerKeyId(jwtDetails.getId() + "_sig"); - jwtSignerService.setDefaultSigningAlgorithmName(jwtDetails.getSignature()); - JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm(); - _logger.trace(" signingAlg {}" , signingAlg); - jwtToken = new SignedJWT(new JWSHeader(signingAlg), jwtClaims); + new DefaultJwtSigningAndValidationService( + jwtDetails.getSignatureKey(), + jwtDetails.getId() + "_sig", + jwtDetails.getSignature() + ); + + jwtToken = new SignedJWT( + new JWSHeader(jwtSignerService.getDefaultSigningAlgorithm()), + jwtClaims + ); // sign it with the server's key jwtSignerService.signJwt((SignedJWT) jwtToken); return jwtToken; @@ -127,22 +126,14 @@ public class JwtAdapter extends AbstractAuthorizeAdapter { @Override public Object encrypt(Object data, String algorithmKey, String algorithm) { if(!jwtDetails.getAlgorithm().equalsIgnoreCase("none")) { - JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+jwtDetails.getAlgorithmKey()+"]}"); try { DefaultJwtEncryptionAndDecryptionService jwtEncryptionService = - new DefaultJwtEncryptionAndDecryptionService(jwkSetKeyStore); - jwtEncryptionService.setDefaultEncryptionKeyId(jwtDetails.getId() + "_enc"); - jwtEncryptionService.setDefaultAlgorithm(jwtDetails.getAlgorithm()); - JWEAlgorithm encryptAlgorithm = null; - if(jwtDetails.getAlgorithm().startsWith("RSA")) { - encryptAlgorithm = jwtEncryptionService.getDefaultAlgorithm(); - }else { - encryptAlgorithm = JWEAlgorithm.DIR; - } - _logger.trace(" encryptAlgorithm {}" , encryptAlgorithm); - EncryptionMethod encryptionMethod = - jwtEncryptionService.parseEncryptionMethod(jwtDetails.getEncryptionMethod()); - + new DefaultJwtEncryptionAndDecryptionService( + jwtDetails.getAlgorithmKey(), + jwtDetails.getId() + "_enc", + jwtDetails.getAlgorithm() + ); + Payload payload; if(jwtToken instanceof SignedJWT) { payload = ((SignedJWT)jwtToken).getPayload(); @@ -151,9 +142,12 @@ public class JwtAdapter extends AbstractAuthorizeAdapter { } // Example Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM //JWEHeader jweHeader = new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM); - + JWEHeader jweHeader = new JWEHeader( + jwtEncryptionService.getDefaultAlgorithm(jwtDetails.getAlgorithm()), + jwtEncryptionService.parseEncryptionMethod(jwtDetails.getEncryptionMethod()) + ); jweObject = new JWEObject( - new JWEHeader.Builder(new JWEHeader(encryptAlgorithm,encryptionMethod)) + new JWEHeader.Builder(jweHeader) .contentType("JWT") // required to indicate nested JWT .build(), payload); diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java index 6d978f5ab..b1530569e 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java @@ -132,7 +132,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint { e.printStackTrace(); } - _logger.debug("authorizationUrl "+authorizationUrl); + _logger.debug("authorizationUrl {}" , authorizationUrl); return WebContext.redirect(authorizationUrl); } diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/userinfo/endpoint/UserInfoOIDCEndpoint.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/userinfo/endpoint/UserInfoOIDCEndpoint.java index bf22ffe9c..631875b4a 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/userinfo/endpoint/UserInfoOIDCEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/userinfo/endpoint/UserInfoOIDCEndpoint.java @@ -213,19 +213,17 @@ public class UserInfoOIDCEndpoint { && !clientDetails.getSignature().equalsIgnoreCase("none") && clientDetails.getUserInfoResponse().equalsIgnoreCase("ENCRYPTION")) { //需要签名 signed ID token - JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getSignatureKey()+"]}"); DefaultJwtSigningAndValidationService jwtSignerService = null; try { - jwtSignerService = new DefaultJwtSigningAndValidationService(jwkSetKeyStore); + jwtSignerService = new DefaultJwtSigningAndValidationService( + clientDetails.getSignatureKey(), + clientDetails.getClientId() + "_sig", + clientDetails.getSignature()); }catch(Exception e) { _logger.error("Couldn't create Jwt Signing Service",e); } - jwtSignerService.setDefaultSignerKeyId(clientDetails.getClientId() + "_sig"); - jwtSignerService.setDefaultSigningAlgorithmName(clientDetails.getSignature()); - JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm(); - _logger.trace(" signingAlg {}" , signingAlg); userInfoJWTClaims = new JWTClaimsSet .Builder(userInfoJWTClaims) .claim("kid", jwtSignerService.getDefaultSignerKeyId()) @@ -240,30 +238,24 @@ public class UserInfoOIDCEndpoint { && !clientDetails.getAlgorithm().equalsIgnoreCase("none") && clientDetails.getUserInfoResponse().equalsIgnoreCase("SIGNING") ) { - //TODO: 需要加密 - JWKSetKeyStore jwkSetKeyStore_Enc = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getAlgorithmKey()+"]}"); + // 需要加密 try { DefaultJwtEncryptionAndDecryptionService jwtEncryptionService = - new DefaultJwtEncryptionAndDecryptionService(jwkSetKeyStore_Enc); - jwtEncryptionService.setDefaultEncryptionKeyId(clientDetails.getClientId() + "_enc"); - jwtEncryptionService.setDefaultAlgorithm(clientDetails.getAlgorithm()); - JWEAlgorithm encryptAlgorithm = null; - if(clientDetails.getAlgorithm().startsWith("RSA")) { - encryptAlgorithm = jwtEncryptionService.getDefaultAlgorithm(); - }else { - encryptAlgorithm = JWEAlgorithm.DIR; - } - _logger.trace(" encryptAlgorithm {}" , encryptAlgorithm); - EncryptionMethod encryptionMethod = - jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod()); + new DefaultJwtEncryptionAndDecryptionService( + clientDetails.getAlgorithmKey(), + clientDetails.getClientId() + "_enc", + clientDetails.getAlgorithm()); Payload payload = userInfoJWTClaims.toPayload(); // Example Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM //JWEHeader jweHeader = new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM); + JWEHeader jweHeader = new JWEHeader( + jwtEncryptionService.getDefaultAlgorithm(clientDetails.getAlgorithm()), + jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod())); JWEObject jweObject = new JWEObject( - new JWEHeader.Builder(new JWEHeader(encryptAlgorithm,encryptionMethod)) + new JWEHeader.Builder(jweHeader) .contentType("JWT") // required to indicate nested JWT .build(), payload); diff --git a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oidc/idtoken/OIDCIdTokenEnhancer.java b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oidc/idtoken/OIDCIdTokenEnhancer.java index 334735478..561bcbdbc 100644 --- a/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oidc/idtoken/OIDCIdTokenEnhancer.java +++ b/maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oidc/idtoken/OIDCIdTokenEnhancer.java @@ -37,7 +37,6 @@ import org.maxkey.authz.oauth2.provider.OAuth2Authentication; import org.maxkey.authz.oauth2.provider.OAuth2Request; import org.maxkey.authz.oauth2.provider.token.TokenEnhancer; import org.maxkey.configuration.oidc.OIDCProviderMetadata; -import org.maxkey.crypto.jose.keystore.JWKSetKeyStore; import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService; import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService; import org.maxkey.entity.apps.oauth2.provider.ClientDetails; @@ -48,9 +47,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; -import com.nimbusds.jose.EncryptionMethod; import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWEHeader; import com.nimbusds.jose.JWEObject; import com.nimbusds.jose.JWSAlgorithm; @@ -71,8 +68,6 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer { private OIDCProviderMetadata providerMetadata; - - private ClientDetailsService clientDetailsService; public void setProviderMetadata(OIDCProviderMetadata providerMetadata) { @@ -94,12 +89,13 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer { JWSAlgorithm signingAlg = null; try {//jwtSignerService if (StringUtils.isNotBlank(clientDetails.getSignature()) && !clientDetails.getSignature().equalsIgnoreCase("none")) { - JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getSignatureKey()+"]}"); - jwtSignerService = new DefaultJwtSigningAndValidationService(jwkSetKeyStore); - jwtSignerService.setDefaultSignerKeyId(clientDetails.getClientId() + "_sig"); - jwtSignerService.setDefaultSigningAlgorithmName(clientDetails.getSignature()); + jwtSignerService = new DefaultJwtSigningAndValidationService( + clientDetails.getSignatureKey(), + clientDetails.getClientId() + "_sig", + clientDetails.getSignature() + ); + signingAlg = jwtSignerService.getDefaultSigningAlgorithm(); - _logger.trace(" signingAlg {}" , signingAlg); } }catch(Exception e) { _logger.error("Couldn't create Jwt Signing Service",e); @@ -118,7 +114,10 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer { * @see http://openid.net/specs/openid-connect-core-1_0.html#SelfIssuedDiscovery * 7. Self-Issued OpenID Provider */ - if(providerMetadata.getIssuer().equalsIgnoreCase("https://self-issued.me") && jwtSignerService != null){ + if(clientDetails.getIssuer()!=null + && jwtSignerService != null + && clientDetails.getIssuer().equalsIgnoreCase("https://self-issued.me") + ){ builder.claim("sub_jwk", jwtSignerService.getAllPublicKeys().get(jwtSignerService.getDefaultSignerKeyId())); } @@ -161,30 +160,26 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer { } }else if (StringUtils.isNotBlank(clientDetails.getAlgorithm()) && !clientDetails.getAlgorithm().equalsIgnoreCase("none")) { - JWKSetKeyStore jwkSetKeyStore_Enc = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getAlgorithmKey()+"]}"); try { DefaultJwtEncryptionAndDecryptionService jwtEncryptionService = - new DefaultJwtEncryptionAndDecryptionService(jwkSetKeyStore_Enc); - jwtEncryptionService.setDefaultEncryptionKeyId(clientDetails.getClientId() + "_enc"); - jwtEncryptionService.setDefaultAlgorithm(clientDetails.getAlgorithm()); - JWEAlgorithm encryptAlgorithm = null; - if(clientDetails.getAlgorithm().startsWith("RSA")) { - encryptAlgorithm = jwtEncryptionService.getDefaultAlgorithm(); - }else { - encryptAlgorithm = JWEAlgorithm.DIR; - } - _logger.trace(" encryptAlgorithm {}" , encryptAlgorithm); - EncryptionMethod encryptionMethod = - jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod()); - + new DefaultJwtEncryptionAndDecryptionService( + clientDetails.getAlgorithmKey(), + clientDetails.getClientId() + "_enc", + clientDetails.getAlgorithm() + ); Payload payload = builder.build().toPayload(); // Example Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM //JWEHeader jweHeader = new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM); + JWEHeader jweHeader = new JWEHeader( + jwtEncryptionService.getDefaultAlgorithm(clientDetails.getAlgorithm()), + jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod()) + ); JWEObject jweObject = new JWEObject( - new JWEHeader.Builder(new JWEHeader(encryptAlgorithm,encryptionMethod)) + new JWEHeader.Builder(jweHeader) .contentType("JWT") // required to indicate nested JWT .build(), payload); + jwtEncryptionService.encryptJwt(jweObject); idTokenString = jweObject.serialize(); } catch (NoSuchAlgorithmException | InvalidKeySpecException | JOSEException e) {