dev.fitko.fitconnect.core.crypto.JWECryptoService Maven / Gradle / Ivy
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 - 2025 Weber Informatics LLC | Privacy Policy