// Path: src/main/java/com/hyperwallet/clientsdk/HyperwalletException.java
// public class HyperwalletException extends RuntimeException {
// 
//     private static final long serialVersionUID = 1L;
// 
//     private Response response = null;
//     private String errorMessage;
//     private String errorCode;
//     private List<String> relatedResources;
//     private HyperwalletErrorList hyperwalletErrorList;
// 
//     public HyperwalletException(final Exception e) {
//         super(e);
//     }
// 
//     public HyperwalletException(final Response response, final int code, final String message) {
//         super(message);
// 
//         this.response = response;
//         errorCode = Integer.toString(code);
//         errorMessage = message;
//     }
// 
//     public HyperwalletException(final Response response, final int code, final String message, final Exception e) {
//         super(e);
// 
//         this.response = response;
//         errorCode = Integer.toString(code);
//         errorMessage = message;
//     }
// 
//     public HyperwalletException(final Response response, final HyperwalletErrorList hyperwalletErrorList) {
//         super(hyperwalletErrorList.getErrors().get(0).getMessage());
// 
//         this.response = response;
//         this.hyperwalletErrorList = hyperwalletErrorList;
//         HyperwalletError error = this.hyperwalletErrorList.getErrors().get(0);
//         errorCode = error.getCode();
//         errorMessage = error.getMessage();
//         relatedResources = error.getRelatedResources();
//     }
// 
//     public HyperwalletException(final String errorMessage) {
//         super(errorMessage);
// 
//         this.errorMessage = errorMessage;
//     }
// 
//     public Response getResponse() {
//         return response;
//     }
// 
//     public String getErrorMessage() {
//         return errorMessage;
//     }
// 
//     public String getErrorCode() {
//         return errorCode;
//     }
// 
//     public List<String> getRelatedResources() {
//         return relatedResources;
//     }
// 
//     public List<HyperwalletError> getHyperwalletErrors() {
//         return hyperwalletErrorList != null ? hyperwalletErrorList.getErrors() : null;
//     }
// }


import com.hyperwallet.clientsdk.HyperwalletException;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.JWEEncrypter;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.ECDHDecrypter;
import com.nimbusds.jose.crypto.ECDHEncrypter;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.crypto.ECDSAVerifier;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyType;
import com.nimbusds.jose.jwk.RSAKey;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
                        .keyID(clientPrivateKey.getKeyID())
                        .criticalParams(new HashSet<>(Collections.singletonList(EXPIRATION)))
                        .customParam(EXPIRATION, getJWSExpirationMillis()).build(),
                new Payload(body));

        jwsObject.sign(jwsSigner);

        JWEObject jweObject = new JWEObject(
                new JWEHeader.Builder(encryptionAlgorithm, encryptionMethod)
                        .keyID(hyperwalletPublicKey.getKeyID()).build(),
                new Payload(jwsObject));

        jweObject.encrypt(jweEncrypter);

        return jweObject.serialize();
    }

    public String decrypt(String body) throws ParseException, IOException, JOSEException {

        JWK privateKeyToDecrypt = getKeyByAlgorithm(loadKeySet(clientPrivateKeySetLocation), encryptionAlgorithm);
        JWK publicKeyToSign = getKeyByAlgorithm(loadKeySet(hyperwalletKeySetLocation), signAlgorithm);
        JWEDecrypter jweDecrypter = getJWEDecrypter(privateKeyToDecrypt);
        JWSVerifier jwsVerifier = getJWSVerifier(publicKeyToSign);

        JWEObject jweObject = JWEObject.parse(body);
        jweObject.decrypt(jweDecrypter);
        JWSObject jwsObject = jweObject.getPayload().toJWSObject();
        verifySignatureExpirationDate(jwsObject.getHeader().getCustomParam(EXPIRATION));
        boolean verifyStatus = jwsObject.verify(jwsVerifier);
        if (!verifyStatus) {
// Path: src/main/java/com/hyperwallet/clientsdk/HyperwalletException.java
// public class HyperwalletException extends RuntimeException {
// 
//     private static final long serialVersionUID = 1L;
// 
//     private Response response = null;
//     private String errorMessage;
//     private String errorCode;
//     private List<String> relatedResources;
//     private HyperwalletErrorList hyperwalletErrorList;
// 
//     public HyperwalletException(final Exception e) {
//         super(e);
//     }
// 
//     public HyperwalletException(final Response response, final int code, final String message) {
//         super(message);
// 
//         this.response = response;
//         errorCode = Integer.toString(code);
//         errorMessage = message;
//     }
// 
//     public HyperwalletException(final Response response, final int code, final String message, final Exception e) {
//         super(e);
// 
//         this.response = response;
//         errorCode = Integer.toString(code);
//         errorMessage = message;
//     }
// 
//     public HyperwalletException(final Response response, final HyperwalletErrorList hyperwalletErrorList) {
//         super(hyperwalletErrorList.getErrors().get(0).getMessage());
// 
//         this.response = response;
//         this.hyperwalletErrorList = hyperwalletErrorList;
//         HyperwalletError error = this.hyperwalletErrorList.getErrors().get(0);
//         errorCode = error.getCode();
//         errorMessage = error.getMessage();
//         relatedResources = error.getRelatedResources();
//     }
// 
//     public HyperwalletException(final String errorMessage) {
//         super(errorMessage);
// 
//         this.errorMessage = errorMessage;
//     }
// 
//     public Response getResponse() {
//         return response;
//     }
// 
//     public String getErrorMessage() {
//         return errorMessage;
//     }
// 
//     public String getErrorCode() {
//         return errorCode;
//     }
// 
//     public List<String> getRelatedResources() {
//         return relatedResources;
//     }
// 
//     public List<HyperwalletError> getHyperwalletErrors() {
//         return hyperwalletErrorList != null ? hyperwalletErrorList.getErrors() : null;
//     }
// }


// Path: src/main/java/com/hyperwallet/clientsdk/util/HyperwalletEncryption.java
import com.hyperwallet.clientsdk.HyperwalletException;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.JWEEncrypter;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.ECDHDecrypter;
import com.nimbusds.jose.crypto.ECDHEncrypter;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jose.crypto.ECDSAVerifier;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyType;
import com.nimbusds.jose.jwk.RSAKey;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

                        .keyID(clientPrivateKey.getKeyID())
                        .criticalParams(new HashSet<>(Collections.singletonList(EXPIRATION)))
                        .customParam(EXPIRATION, getJWSExpirationMillis()).build(),
                new Payload(body));

        jwsObject.sign(jwsSigner);

        JWEObject jweObject = new JWEObject(
                new JWEHeader.Builder(encryptionAlgorithm, encryptionMethod)
                        .keyID(hyperwalletPublicKey.getKeyID()).build(),
                new Payload(jwsObject));

        jweObject.encrypt(jweEncrypter);

        return jweObject.serialize();
    }

    public String decrypt(String body) throws ParseException, IOException, JOSEException {

        JWK privateKeyToDecrypt = getKeyByAlgorithm(loadKeySet(clientPrivateKeySetLocation), encryptionAlgorithm);
        JWK publicKeyToSign = getKeyByAlgorithm(loadKeySet(hyperwalletKeySetLocation), signAlgorithm);
        JWEDecrypter jweDecrypter = getJWEDecrypter(privateKeyToDecrypt);
        JWSVerifier jwsVerifier = getJWSVerifier(publicKeyToSign);

        JWEObject jweObject = JWEObject.parse(body);
        jweObject.decrypt(jweDecrypter);
        JWSObject jwsObject = jweObject.getPayload().toJWSObject();
        verifySignatureExpirationDate(jwsObject.getHeader().getCustomParam(EXPIRATION));
        boolean verifyStatus = jwsObject.verify(jwsVerifier);
        if (!verifyStatus) {
            throw new HyperwalletException("JWS signature is incorrect");