All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.fitko.fitconnect.core.crypto.JWECryptoService Maven / Gradle / Ivy

Go to download

Library that provides client access to the FIT-Connect api-endpoints for sending, subscribing and routing

There is a newer version: 2.3.5
Show newest version
package dev.fitko.fitconnect.core.crypto;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.jwk.RSAKey;
import dev.fitko.fitconnect.api.exceptions.internal.DecryptionException;
import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException;
import dev.fitko.fitconnect.api.services.crypto.CryptoService;
import dev.fitko.fitconnect.api.services.crypto.MessageDigestService;
import dev.fitko.fitconnect.core.utils.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;

import static dev.fitko.fitconnect.core.crypto.constants.CryptoConstants.DEFAULT_JWE_ALGORITHM;
import static dev.fitko.fitconnect.core.crypto.constants.CryptoConstants.DEFAULT_JWE_ENCRYPTION_METHOD;

public class JWECryptoService implements CryptoService {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWECryptoService.class);
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private final MessageDigestService messageDigestService;

    public JWECryptoService(final MessageDigestService messageDigestService) {
        this.messageDigestService = messageDigestService;
    }

    public JWECryptoService() {
        messageDigestService = new HashService();
    }

    @Override
    public byte[] decryptToBytes(final RSAKey privateKey, final String encryptedData) throws DecryptionException {
        return decrypt(privateKey, encryptedData).toBytes();
    }

    @Override
    public String encryptObject(final RSAKey encryptionKey, final Object obj, final String contentType) throws EncryptionException {
        try {
            final Payload payload = new Payload(MAPPER.writeValueAsBytes(obj));
            return encrypt(encryptionKey, payload, contentType).serialize();
        } catch (final JsonProcessingException e) {
            throw new EncryptionException(e.getMessage(), e);
        }
    }

    @Override
    public String encryptBytes(final RSAKey publicKey, final byte[] bytes, final String contentType) throws EncryptionException {
        final Payload payload = new Payload(bytes);
        return encrypt(publicKey, payload, contentType).serialize();
    }

    @Override
    public JWEObject encryptInputStream(final RSAKey publicKey, final InputStream inputStream, final String contentType) throws EncryptionException {
        final Payload payload;
        try {
            payload = new Payload(inputStream.readAllBytes());
        } catch (final IOException e) {
            throw new EncryptionException(e.getMessage(), e);
        }
        return encrypt(publicKey, payload, contentType);
    }

    @Override
    public String hashBytes(final byte[] data) {
        final byte[] hash = messageDigestService.createHash(data);
        return messageDigestService.toHexString(hash);
    }

    @Override
    public String hashStream(final InputStream inputStream) {
        final byte[] hash = messageDigestService.createHash(inputStream);
        return messageDigestService.toHexString(hash);
    }

    private JWEObject encrypt(final RSAKey publicKey, final Payload payload, final String contentType) throws EncryptionException {
        try {
            return encryptPayload(publicKey, payload, contentType);
        } catch (final JOSEException e) {
            throw new EncryptionException(e.getMessage(), e);
        }
    }

    private Payload decrypt(final RSAKey privateKey, final String encData) throws DecryptionException {
        try {
            final var start = StopWatch.start();
            printAvailableVmMemory();
            final JWEObject jwe = JWEObject.parse(encData);
            jwe.decrypt(new RSADecrypter(privateKey));
            LOGGER.trace("Decryption took {} ", StopWatch.stop(start));
            return jwe.getPayload();
        } catch (final ParseException | IllegalStateException | JOSEException e) {
            throw new DecryptionException(e.getMessage(), e);
        }
    }

    private JWEHeader getJWEHeader(final String keyID, final String contentType) {
        return new JWEHeader.Builder(DEFAULT_JWE_ALGORITHM, DEFAULT_JWE_ENCRYPTION_METHOD)
                .contentType(contentType)
                .keyID(keyID)
                .build();
    }

    private RSAEncrypter getEncrypter(final RSAKey publicKey) {
        try {
            return new RSAEncrypter(publicKey.toRSAPublicKey());
        } catch (final JOSEException e) {
            throw new EncryptionException("RSAEncrypter could not be initialized", e);
        }
    }

    private JWEObject encryptPayload(final RSAKey publicKey, final Payload payload, final String contentType) throws JOSEException, EncryptionException {
        final String keyID = getIdFromPublicKey(publicKey);
        final JWEObject jwe = new JWEObject(getJWEHeader(keyID, contentType), payload);
        final var start = StopWatch.start();
        jwe.encrypt(getEncrypter(publicKey));
        printAvailableVmMemory();
        checkIfJWEObjectIsEncrypted(jwe);
        LOGGER.trace("Encryption took {} ", StopWatch.stop(start));
        return jwe;
    }


    private void checkIfJWEObjectIsEncrypted(final JWEObject jwe) throws EncryptionException {
        if (!jwe.getState().equals(JWEObject.State.ENCRYPTED)) {
            throw new EncryptionException("JWE object is not encrypted");
        }
    }

    private String getIdFromPublicKey(final RSAKey publicKey) throws EncryptionException {
        final String keyID = publicKey.getKeyID();
        if (keyID == null || keyID.isEmpty()) {
            throw new EncryptionException("public key has no keyID");
        }
        return keyID;
    }

    private void printAvailableVmMemory() {
        LOGGER.trace("Currently used VM memory {} MB", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy