dev.fitko.fitconnect.core.crypto.JWECryptoService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of client Show documentation
Show all versions of client Show documentation
Library that provides client access to the FIT-Connect api-endpoints for sending, subscribing and
routing
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);
}
}