From eacfda768c020f015c076d2075fac82d904c11fe Mon Sep 17 00:00:00 2001
From: Martin Vogel <martin.vogel@sinc.de>
Date: Fri, 8 Dec 2023 09:39:23 +0000
Subject: [PATCH] #1244 Add Content-Type to JWE Encryption Header

---
 .../fitko/fitconnect/api/services/Sender.java |  6 ++--
 .../api/services/crypto/CryptoService.java    |  6 ++--
 .../cli/keygen/JWKGeneratorTest.java          |  2 +-
 .../strategies/SendNewSubmissionStrategy.java |  6 ++--
 .../fitconnect/client/SenderClientTest.java   |  2 +-
 .../client/SubscriberClientTest.java          | 28 +++++++++----------
 .../fitconnect/core/SubmissionSender.java     | 12 ++++----
 .../core/crypto/JWECryptoService.java         | 26 ++++++++---------
 .../fitconnect/core/SubmissionSenderTest.java | 17 ++++++-----
 .../core/crypto/JWECryptoServiceTest.java     | 26 +++++++++++++++--
 .../events/SecurityEventTokenServiceTest.java | 18 ++++++------
 .../integrationtests/SenderClientIT.java      |  8 +++---
 12 files changed, 90 insertions(+), 67 deletions(-)

diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java b/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java
index e5534d1ee..e744ae0e1 100644
--- a/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java
+++ b/api/src/main/java/dev/fitko/fitconnect/api/services/Sender.java
@@ -54,22 +54,24 @@ public interface Sender {
      *
      * @param publicKey the public encryption key for encryption of {@link Data}
      * @param data      the {@link Data} payload that should be encrypted
+     * @param contentType MIME content type of the bytes to encrypt
      * @return the JWE-encrypted {@link Data}
      *
      * @throws EncryptionException if the encryption fails due to an invalid key or corrupt data
      */
-    String encryptBytes(RSAKey publicKey, byte[] data) throws EncryptionException;
+    String encryptBytes(RSAKey publicKey, byte[] data, String contentType) throws EncryptionException;
 
     /**
      * Encrypts an object with JWE (JSON-Web-Encryption).
      *
      * @param publicKey the public encryption key
      * @param object  the data payload that should be encrypted
+     * @param contentType MIME content type of the object to encrypt
      * @return the JWE-encrypted {@link Data}
      *
      * @throws EncryptionException if the encryption fails due to an invalid key or corrupt data
      */
-    String encryptObject(RSAKey publicKey, Object object) throws EncryptionException;
+    String encryptObject(RSAKey publicKey, Object object, String contentType) throws EncryptionException;
 
     /**
      * Create message digest (SHA-512) of a given byte[]
diff --git a/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java b/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java
index 890ffc9f1..abc169926 100644
--- a/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java
+++ b/api/src/main/java/dev/fitko/fitconnect/api/services/crypto/CryptoService.java
@@ -31,22 +31,24 @@ public interface CryptoService {
      *
      * @param encryptionKey RSA public key for encryption of string payload
      * @param obj   object  that should be encrypted
+     * @param contentType MIME content type of the object to encrypt
      * @return Hex string of the encrypted JWE object
      *
      * @throws EncryptionException if the payload cannot be encrypted or there was an issue with the key
      */
-    String encryptObject(RSAKey encryptionKey, Object obj);
+    String encryptObject(RSAKey encryptionKey, Object obj, String contentType);
 
     /**
      * Encrypts a byte[] payload with the given public key.
      *
      * @param encryptionKey RSA public key the payload is encrypted with
      * @param bytes     byte[] of the data that should be encrypted
+     * @param contentType MIME content type of the string to encrypt
      * @return Hex string of the encrypted JWE object
      *
      * @throws EncryptionException if the payload cannot be encrypted or there was an issue with the key
      */
-    String encryptBytes(RSAKey encryptionKey, byte[] bytes) throws EncryptionException;
+    String encryptBytes(RSAKey encryptionKey, byte[] bytes, String contentType) throws EncryptionException;
 
     /**
      * Creates a message digest hash from the given input byte[]
diff --git a/cli/src/test/java/dev/fitko/fitconnect/cli/keygen/JWKGeneratorTest.java b/cli/src/test/java/dev/fitko/fitconnect/cli/keygen/JWKGeneratorTest.java
index 772162da2..44b9d9767 100644
--- a/cli/src/test/java/dev/fitko/fitconnect/cli/keygen/JWKGeneratorTest.java
+++ b/cli/src/test/java/dev/fitko/fitconnect/cli/keygen/JWKGeneratorTest.java
@@ -102,7 +102,7 @@ class JWKGeneratorTest {
         // When
         final JWECryptoService cryptoService = new JWECryptoService(null);
 
-        final String encryptedData = cryptoService.encryptBytes(publicKey.toRSAKey(), data.getBytes(StandardCharsets.UTF_8));
+        final String encryptedData = cryptoService.encryptBytes(publicKey.toRSAKey(), data.getBytes(StandardCharsets.UTF_8), "application/json");
         final byte[] decryptedData = cryptoService.decryptToBytes(privateKey.toRSAKey(), encryptedData);
 
         // Then
diff --git a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java
index c472e83ff..d4909566d 100644
--- a/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java
+++ b/client/src/main/java/dev/fitko/fitconnect/client/sender/strategies/SendNewSubmissionStrategy.java
@@ -71,10 +71,10 @@ public class SendNewSubmissionStrategy {
         }
 
         LOGGER.info("Encrypting submission data ...");
-        final String encryptedData = sender.encryptBytes(encryptionKey, sendableSubmission.getData().getBytes(StandardCharsets.UTF_8));
+        final String encryptedData = sender.encryptBytes(encryptionKey, sendableSubmission.getData().getBytes(StandardCharsets.UTF_8), sendableSubmission.getDataMimeType());
 
         LOGGER.info("Encrypting metadata ...");
-        final String encryptedMetadata = sender.encryptObject(encryptionKey, metadata);
+        final String encryptedMetadata = sender.encryptObject(encryptionKey, metadata, MimeType.APPLICATION_JSON.value());
 
         final var startTimeSubmissionUpload = StopWatch.start();
         final Submission submission = sender.sendSubmission(buildSubmitSubmission(announcedSubmissionId, encryptedData, encryptedMetadata));
@@ -167,7 +167,7 @@ public class SendNewSubmissionStrategy {
     }
 
     private AttachmentPayload encryptAndHashAttachment(final RSAKey encryptionKey, final Attachment attachment) {
-        final String encryptedAttachment = sender.encryptBytes(encryptionKey, attachment.getDataAsBytes());
+        final String encryptedAttachment = sender.encryptBytes(encryptionKey, attachment.getDataAsBytes(), attachment.getMimeType());
         final String hashedBytes = sender.createHash(attachment.getDataAsBytes());
         return AttachmentPayload.builder()
                 .attachmentId(UUID.randomUUID())
diff --git a/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java
index b468f8731..e84db60b8 100644
--- a/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java
+++ b/client/src/test/java/dev/fitko/fitconnect/client/SenderClientTest.java
@@ -292,7 +292,7 @@ public class SenderClientTest {
     void testEncryptionError() {
 
         // Given
-        when(senderMock.encryptBytes(any(), any())).thenThrow(new EncryptionException("Encryption failed"));
+        when(senderMock.encryptBytes(any(), any(), anyString())).thenThrow(new EncryptionException("Encryption failed"));
 
         final var submission = SendableSubmission.Builder()
                 .setDestination(destinationId)
diff --git a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java
index 0c251d820..759fbeb07 100644
--- a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java
+++ b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java
@@ -315,8 +315,8 @@ class SubscriberClientTest {
         final RSAKey encryptionKey = privateKey;
         final RSAKey decryptionKey = encryptionKey.toPublicJWK();
 
-        final String encryptedData = cryptoService.encryptObject(decryptionKey, dataPayload);
-        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes);
+        final String encryptedData = cryptoService.encryptObject(decryptionKey, dataPayload, "application/json");
+        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes, "application/json");
 
         final var submission = new Submission();
         submission.setSubmissionId(submissionId);
@@ -474,8 +474,8 @@ class SubscriberClientTest {
         final RSAKey encryptionKey = privateKey;
         final RSAKey decryptionKey = encryptionKey.toPublicJWK();
 
-        final String encryptedData = cryptoService.encryptObject(decryptionKey, dataPayload);
-        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes);
+        final String encryptedData = cryptoService.encryptObject(decryptionKey, dataPayload, "application/json");
+        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes, "application/json");
 
         final var submission = new Submission();
         submission.setSubmissionId(submissionId);
@@ -523,8 +523,8 @@ class SubscriberClientTest {
         final var metadata = new Metadata();
         metadata.setContentStructure(contentStructure);
 
-        final String encryptedData = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(data));
-        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(metadata));
+        final String encryptedData = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(data), "application/json");
+        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(metadata), "application/json");
         final var metadataBytes = mapper.writeValueAsBytes(metadata);
         final var dataBytes = mapper.writeValueAsBytes(data);
 
@@ -583,8 +583,8 @@ class SubscriberClientTest {
         final var metadata = new Metadata();
         metadata.setContentStructure(contentStructure);
 
-        final String encryptedData = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(data));
-        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(metadata));
+        final String encryptedData = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(data), "application/json");
+        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, mapper.writeValueAsString(metadata), "application/json");
         final var metadataBytes = mapper.writeValueAsBytes(metadata);
         final var dataBytes = mapper.writeValueAsBytes(data);
 
@@ -646,8 +646,8 @@ class SubscriberClientTest {
         final var metadata = new Metadata();
         metadata.setContentStructure(contentStructure);
 
-        final String encryptedData = cryptoService.encryptBytes(encryptionKey, mapper.writeValueAsString(data).getBytes());
-        final String encryptedMetadata = cryptoService.encryptBytes(encryptionKey, mapper.writeValueAsString(metadata).getBytes());
+        final String encryptedData = cryptoService.encryptBytes(encryptionKey, mapper.writeValueAsString(data).getBytes(), "application/json");
+        final String encryptedMetadata = cryptoService.encryptBytes(encryptionKey, mapper.writeValueAsString(metadata).getBytes(), "application/json");
         final var metadataBytes = mapper.writeValueAsBytes(metadata);
         final var dataBytes = mapper.writeValueAsBytes(data);
 
@@ -721,8 +721,8 @@ class SubscriberClientTest {
         final RSAKey encryptionKey = privateKey;
         final RSAKey decryptionKey = encryptionKey.toPublicJWK();
 
-        final String encryptedData = cryptoService.encryptBytes(decryptionKey, dataPayload.getBytes(StandardCharsets.UTF_8));
-        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes);
+        final String encryptedData = cryptoService.encryptBytes(decryptionKey, dataPayload.getBytes(StandardCharsets.UTF_8), "application/json");
+        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes, "application/json");
 
         final var submission = new Submission();
         submission.setSubmissionId(submissionId);
@@ -784,8 +784,8 @@ class SubscriberClientTest {
         final RSAKey encryptionKey = privateKey;
         final RSAKey decryptionKey = encryptionKey.toPublicJWK();
 
-        final String encryptedData = cryptoService.encryptBytes(decryptionKey, dataPayload.getBytes(StandardCharsets.UTF_8));
-        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes);
+        final String encryptedData = cryptoService.encryptBytes(decryptionKey, dataPayload.getBytes(StandardCharsets.UTF_8), "application/json");
+        final String encryptedMetadata = cryptoService.encryptBytes(decryptionKey, metadataBytes, "application/json");
 
         final var submission = new Submission();
         submission.setSubmissionId(submissionId);
diff --git a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java
index 611403975..53c1dc4c6 100644
--- a/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java
+++ b/core/src/main/java/dev/fitko/fitconnect/core/SubmissionSender.java
@@ -65,13 +65,13 @@ public class SubmissionSender implements Sender {
     }
 
     @Override
-    public String encryptBytes(final RSAKey publicKey, final byte[] data) throws EncryptionException {
-        return cryptoService.encryptBytes(publicKey, data);
+    public String encryptBytes(final RSAKey publicKey, final byte[] data, final String contentType) throws EncryptionException {
+        return cryptoService.encryptBytes(publicKey, data, contentType);
     }
 
     @Override
-    public String encryptObject(final RSAKey encryptionKey, final Object obj) throws EncryptionException {
-        return cryptoService.encryptObject(encryptionKey, obj);
+    public String encryptObject(final RSAKey encryptionKey, final Object obj, final String contentType) throws EncryptionException {
+        return cryptoService.encryptObject(encryptionKey, obj, contentType);
     }
 
 
@@ -87,13 +87,13 @@ public class SubmissionSender implements Sender {
     }
 
     @Override
-    public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) throws RestApiException{
+    public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) throws RestApiException {
         LOGGER.info("Uploading attachment {} for submission {}", attachmentId, submissionId);
         submissionService.uploadAttachment(submissionId, attachmentId, encryptedAttachment);
     }
 
     @Override
-    public Destination getDestination(final UUID destinationId)  throws RestApiException {
+    public Destination getDestination(final UUID destinationId) throws RestApiException {
         LOGGER.info("Loading  destination {}", destinationId);
         return submissionService.getDestination(destinationId);
     }
diff --git a/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java b/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java
index 1f7b084e7..c315dc042 100644
--- a/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java
+++ b/core/src/main/java/dev/fitko/fitconnect/core/crypto/JWECryptoService.java
@@ -45,19 +45,19 @@ public class JWECryptoService implements CryptoService {
     }
 
     @Override
-    public String encryptObject(final RSAKey encryptionKey, final Object obj) throws EncryptionException {
+    public String encryptObject(final RSAKey encryptionKey, final Object obj, final String contentType) throws EncryptionException {
         try {
             final Payload payload = new Payload(MAPPER.writeValueAsString(obj));
-            return encrypt(encryptionKey, payload);
+            return encrypt(encryptionKey, payload, contentType);
         } catch (final JsonProcessingException e) {
             throw new EncryptionException(e.getMessage(), e);
         }
     }
 
     @Override
-    public String encryptBytes(final RSAKey publicKey, final byte[] bytes) throws EncryptionException {
+    public String encryptBytes(final RSAKey publicKey, final byte[] bytes, final String contentType) throws EncryptionException {
         final Payload payload = new Payload(bytes);
-        return encrypt(publicKey, payload);
+        return encrypt(publicKey, payload, contentType);
     }
 
     @Override
@@ -66,13 +66,12 @@ public class JWECryptoService implements CryptoService {
         return messageDigestService.toHexString(hash);
     }
 
-    private String encrypt(final RSAKey publicKey, final Payload payload) throws EncryptionException {
+    private String encrypt(final RSAKey publicKey, final Payload payload, final String contentType) throws EncryptionException {
         try {
             final KeyGenerator keyGenerator = KeyGenerator.getInstance(DEFAULT_SYMMETRIC_ENCRYPTION_ALGORITHM);
             keyGenerator.init(DEFAULT_JWE_ENCRYPTION_METHOD.cekBitLength());
             final SecretKey cek = keyGenerator.generateKey();
-            final String keyID = getIdFromPublicKey(publicKey);
-            return encryptPayload(publicKey, payload, cek, keyID);
+            return encryptPayload(publicKey, payload, cek, contentType);
         } catch (final NoSuchAlgorithmException | JOSEException e) {
             throw new EncryptionException(e.getMessage(), e);
         }
@@ -91,14 +90,10 @@ public class JWECryptoService implements CryptoService {
         }
     }
 
-    private JWEObject getJWEObject(final String keyID, final Payload payload) {
-        return new JWEObject(getJWEHeader(keyID), payload);
-    }
-
-    private JWEHeader getJWEHeader(final String keyID) {
+    private JWEHeader getJWEHeader(final String keyID, final String contentType) {
         return new JWEHeader.Builder(DEFAULT_JWE_ALGORITHM, DEFAULT_JWE_ENCRYPTION_METHOD)
                 .compressionAlgorithm(DEFAULT_JWE_COMPRESSION_ALGORITHM)
-                .contentType("application/json")
+                .contentType(contentType)
                 .keyID(keyID)
                 .build();
     }
@@ -111,8 +106,9 @@ public class JWECryptoService implements CryptoService {
         }
     }
 
-    private String encryptPayload(final RSAKey publicKey, final Payload payload, final SecretKey cek, final String keyID) throws JOSEException, EncryptionException {
-        final JWEObject jwe = getJWEObject(keyID, payload);
+    private String encryptPayload(final RSAKey publicKey, final Payload payload, final SecretKey cek, 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, cek));
         printAvailableVmMemory();
diff --git a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java
index 27cb30f7e..b96deadfe 100644
--- a/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java
+++ b/core/src/test/java/dev/fitko/fitconnect/core/SubmissionSenderTest.java
@@ -55,6 +55,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -96,14 +97,16 @@ public class SubmissionSenderTest {
                 .generate()
                 .toPublicJWK();
 
-        when(cryptoServiceMock.encryptBytes(any(), any())).thenReturn("encryptedString");
+        final byte[] dataToEncrypt = "{\"data\": \"encryptedString\"".getBytes();
+
+        when(cryptoServiceMock.encryptBytes(publicKey, dataToEncrypt, "application/json")).thenReturn("€ncrypt€dD@t@");
 
         // When
-        final String encryptedData = underTest.encryptBytes(publicKey, "data".getBytes());
+        final String encryptedData = underTest.encryptBytes(publicKey, dataToEncrypt, "application/json");
 
         // Then
         assertNotNull(encryptedData);
-        assertThat(encryptedData, is("encryptedString"));
+        assertThat(encryptedData, is("€ncrypt€dD@t@"));
     }
 
     @Test
@@ -204,12 +207,12 @@ public class SubmissionSenderTest {
                 .generate()
                 .toPublicJWK();
 
-        when(cryptoServiceMock.encryptObject(any(), any())).thenReturn("encryptedObject");
+        when(cryptoServiceMock.encryptObject(any(), any(), anyString())).thenReturn("encryptedObject");
 
         final Metadata metadata = new Metadata();
 
         // When
-        final String encryptedMetadata = underTest.encryptObject(publicKey, metadata);
+        final String encryptedMetadata = underTest.encryptObject(publicKey, metadata, "application/json");
 
         // Then
         assertThat(encryptedMetadata, equalTo("encryptedObject"));
@@ -226,12 +229,12 @@ public class SubmissionSenderTest {
                 .toPublicJWK();
 
         // When
-        when(cryptoServiceMock.encryptObject(any(), any())).thenThrow(EncryptionException.class);
+        when(cryptoServiceMock.encryptObject(any(), any(), anyString())).thenThrow(EncryptionException.class);
 
         // Then
         assertThrows(
                 EncryptionException.class,
-                () -> underTest.encryptObject(publicKey, new Metadata()),
+                () -> underTest.encryptObject(publicKey, new Metadata(), "application/json"),
                 "Expected encryptObject() to throw, but nothing was thrown"
         );
     }
diff --git a/core/src/test/java/dev/fitko/fitconnect/core/crypto/JWECryptoServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/crypto/JWECryptoServiceTest.java
index 30b474eda..a91ff1733 100644
--- a/core/src/test/java/dev/fitko/fitconnect/core/crypto/JWECryptoServiceTest.java
+++ b/core/src/test/java/dev/fitko/fitconnect/core/crypto/JWECryptoServiceTest.java
@@ -2,6 +2,8 @@ package dev.fitko.fitconnect.core.crypto;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEObject;
+import com.nimbusds.jose.crypto.RSADecrypter;
 import com.nimbusds.jose.jwk.KeyUse;
 import com.nimbusds.jose.jwk.RSAKey;
 import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
@@ -11,6 +13,7 @@ import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.text.ParseException;
 import java.util.UUID;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -37,7 +40,7 @@ public class JWECryptoServiceTest {
         final RSAKey publicKey = privateKey.toPublicJWK();
 
         // When
-        final String encryptedData = underTest.encryptBytes(publicKey, "some foo".getBytes(StandardCharsets.UTF_8));
+        final String encryptedData = underTest.encryptBytes(publicKey, "some foo".getBytes(StandardCharsets.UTF_8), "text/plain");
 
         // Then
         assertNotNull(encryptedData);
@@ -51,7 +54,7 @@ public class JWECryptoServiceTest {
         final Metadata metadata = new Metadata();
 
         // When
-        final String encryptedData = underTest.encryptObject(publicKey, metadata);
+        final String encryptedData = underTest.encryptObject(publicKey, metadata, "application/json");
 
         // Then
         assertNotNull(encryptedData);
@@ -64,7 +67,7 @@ public class JWECryptoServiceTest {
 
         // Given
         final RSAKey publicKey = privateKey.toPublicJWK();
-        final String dataFromSender = underTest.encryptBytes(publicKey, "some foo".getBytes());
+        final String dataFromSender = underTest.encryptBytes(publicKey, "some foo".getBytes(), "text/plain");
 
         // When
         final byte[] decrypted = underTest.decryptToBytes(privateKey, dataFromSender);
@@ -85,6 +88,23 @@ public class JWECryptoServiceTest {
         assertEquals(underTest.hashBytes(contentToHash), underTest.hashBytes(contentToHash));
     }
 
+    @Test
+    void testContentTypeIsSetInHeader() throws ParseException, JOSEException {
+
+        // Given
+        final RSAKey publicKey = privateKey.toPublicJWK();
+        final String encryptedJWE = underTest.encryptBytes(publicKey, "some data".getBytes(), "text/plain");
+
+        // When
+        final JWEObject jwe = JWEObject.parse(encryptedJWE);
+        jwe.decrypt(new RSADecrypter(privateKey));
+
+        // Then
+        assertNotNull(jwe);
+        assertThat(jwe.getHeader().getContentType(), is("text/plain"));
+
+    }
+
     public static RSAKey generateRsaKey(final int size) throws JOSEException {
         return new RSAKeyGenerator(size)
                 .keyUse(KeyUse.ENCRYPTION)
diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java
index c6a427e9e..67554caba 100644
--- a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java
+++ b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java
@@ -78,12 +78,12 @@ class SecurityEventTokenServiceTest {
     void testAcceptSubmissionEventWithoutProblems() throws JOSEException {
 
         // Given
-        final var encryptedData = cryptoService.encryptObject(encryptionKey, "test data");
-        final var encryptedMetadata = cryptoService.encryptObject(encryptionKey, "test metadata");
+        final var encryptedData = cryptoService.encryptObject(encryptionKey, "test data", "application/json");
+        final var encryptedMetadata = cryptoService.encryptObject(encryptionKey, "test metadata", "application/json");
 
         final var encryptedAttachments = new HashMap<UUID, String>();
-        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment 1"));
-        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment 2"));
+        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment 1", "application/json"));
+        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment 2", "application/json"));
 
         final var submission = new Submission();
         submission.setSubmissionId(UUID.randomUUID());
@@ -115,11 +115,11 @@ class SecurityEventTokenServiceTest {
     void testAcceptSubmissionEventWithProblem() throws JOSEException {
 
         // Given
-        final var encryptedData = cryptoService.encryptObject(encryptionKey, "test data");
-        final var encryptedMetadata = cryptoService.encryptObject(encryptionKey, "test metadata");
+        final var encryptedData = cryptoService.encryptObject(encryptionKey, "test data", "application/json");
+        final var encryptedMetadata = cryptoService.encryptObject(encryptionKey, "test metadata", "application/json");
 
         final var encryptedAttachments = new HashMap<UUID, String>();
-        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment"));
+        encryptedAttachments.put(UUID.randomUUID(), cryptoService.encryptObject(encryptionKey, "test attachment", "application/json"));
 
         final var submission = new Submission();
         submission.setSubmissionId(UUID.randomUUID());
@@ -189,7 +189,7 @@ class SecurityEventTokenServiceTest {
         submission.setSubmissionId(UUID.randomUUID());
         submission.setDestinationId(UUID.randomUUID());
         submission.setCaseId(UUID.randomUUID());
-        submission.setEncryptedData(cryptoService.encryptObject(encryptionKey, "test data"));
+        submission.setEncryptedData(cryptoService.encryptObject(encryptionKey, "test data", "application/json"));
 
         final EventPayload eventPayload = EventPayload.forAcceptEvent(submission);
 
@@ -208,7 +208,7 @@ class SecurityEventTokenServiceTest {
         submission.setSubmissionId(UUID.randomUUID());
         submission.setDestinationId(UUID.randomUUID());
         submission.setCaseId(UUID.randomUUID());
-        submission.setEncryptedMetadata(cryptoService.encryptObject(encryptionKey, "test metadata"));
+        submission.setEncryptedMetadata(cryptoService.encryptObject(encryptionKey, "test metadata", "application/json"));
 
         final EventPayload eventPayload = EventPayload.forAcceptEvent(submission);
 
diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java
index 4084105d4..a94c092d6 100644
--- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java
+++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/SenderClientIT.java
@@ -1,6 +1,5 @@
 package dev.fitko.fitconnect.integrationtests;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.jose.jwk.RSAKey;
 import dev.fitko.fitconnect.api.config.ApplicationConfig;
 import dev.fitko.fitconnect.api.config.defaults.SchemaConfig;
@@ -98,6 +97,7 @@ public class SenderClientIT extends IntegrationTestBase {
         assertThat(receivedSubmission.getAttachments(), hasSize(3));
         assertThat(receivedSubmission.getMetadata().getReplyChannel(), is(ReplyChannel.fromDeMail("test@mail.org")));
         assertThat(new String(receivedSubmission.getAttachments().get(0).getDataAsBytes()), is("Test attachment"));
+        assertThat(receivedSubmission.getAttachments().get(0).getMimeType(), is("text/plain"));
     }
 
     @Test
@@ -185,8 +185,8 @@ public class SenderClientIT extends IntegrationTestBase {
         final File attachmentFile = new File("src/test/resources/attachment.txt");
         final String attachmentData = Files.readString(attachmentFile.toPath());
 
-        final String encryptedData = cryptoService.encryptBytes(encryptionKey, jsonData.getBytes(StandardCharsets.UTF_8));
-        final String encryptedAttachment = cryptoService.encryptBytes(encryptionKey, attachmentData.getBytes(StandardCharsets.UTF_8));
+        final String encryptedData = cryptoService.encryptBytes(encryptionKey, jsonData.getBytes(StandardCharsets.UTF_8), "application/json");
+        final String encryptedAttachment = cryptoService.encryptBytes(encryptionKey, attachmentData.getBytes(StandardCharsets.UTF_8), "text/plain");
 
         final var submissionSchema = new SubmissionSchema();
         submissionSchema.setSchemaUri(URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"));
@@ -219,7 +219,7 @@ public class SenderClientIT extends IntegrationTestBase {
         metadata.setSchema(SchemaConfig.METADATA_V_1_0_0.toString());
         metadata.setContentStructure(contentStructure);
 
-        final String encryptedMetadata = cryptoService.encryptBytes(encryptionKey, new ObjectMapper().writeValueAsBytes(metadata));
+        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, metadata, "application/json");
 
         // When
         final var submission = SendableEncryptedSubmission.Builder()
-- 
GitLab