diff --git a/api/pom.xml b/api/pom.xml
index 10f9df333da56931724b4241c51fc2ada04e5128..f1720e292779a455a2a74708fa65012de4b098ef 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -16,4 +16,15 @@
         <maven.compiler.target>17</maven.compiler.target>
     </properties>
 
+    <dependencies>
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.zalando</groupId>
+            <artifactId>problem</artifactId>
+        </dependency>
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/api/src/main/java/fitconnect/api/Sender.java b/api/src/main/java/fitconnect/api/Sender.java
index c5d1061b0d2c41263ac21131bc35f505dc869c1d..0e76e0a38b5529802e976b0549980607a8100cbf 100644
--- a/api/src/main/java/fitconnect/api/Sender.java
+++ b/api/src/main/java/fitconnect/api/Sender.java
@@ -1,11 +1,7 @@
 package fitconnect.api;
 
+import com.nimbusds.jose.jwk.RSAKey;
 import fitconnect.api.auth.OAuthToken;
-import fitconnect.api.data.Data;
-import fitconnect.api.data.Metadata;
-import fitconnect.api.validation.ValidationResult;
-
-import java.io.ByteArrayInputStream;
 
 /**
  * A technical system that creates a submission via the Submission API.
@@ -22,31 +18,19 @@ public interface Sender {
      */
     OAuthToken retrieveAuthenticationToken(final String clientId, final String clientSecret, String... scope);
 
-    // TODO
-    ValidationResult validateCertificateChain(byte[] chain);
-
     /**
      * Encrypts the submission data with JWE.
      *
-     * @param unencryptedData - unencrypted JSON or XML data
-     * @return encrypted JSON or XML data
+     * @param unencryptedData - unencrypted JSON or XML data as string
+     * @return encrypted JSON or XML data as string
      */
-    Data encryptData(final Data unencryptedData);
+     String encryptData(RSAKey publicKey, String unencryptedData);
 
     /**
-     * Encrypts the submission attachment with JWE.
+     * Encrypts a submission attachment with JWE.
      *
-     * @param unencryptedAttachmentBinary - the unencrypted binary data of the attachment
-     * @return the encrypted binary of the attachment
+     * @param unencryptedAttachment - unencrypted bytes of the attachment
+     * @return encrypted JWE string serialization of the attachment
      */
-    ByteArrayInputStream encryptAttachment(final ByteArrayInputStream unencryptedAttachmentBinary);
-
-    /**
-     * Generates the metadata consisting of the attachment and its hash values.
-     *
-     * @param attachment - the unencrypted binary data of the attachment
-     * @return metadata object
-     */
-    Metadata generateMetadata(byte[] attachment);
-
+    String encryptAttachment(RSAKey publicKey, byte[] unencryptedAttachment);
 }
diff --git a/client/src/main/java/fitconnect/client/impl/SubmissionSender.java b/client/src/main/java/fitconnect/client/impl/SubmissionSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc26e74d6794abdc4fa286c57279879de8b985af
--- /dev/null
+++ b/client/src/main/java/fitconnect/client/impl/SubmissionSender.java
@@ -0,0 +1,34 @@
+package fitconnect.client.impl;
+
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.Sender;
+import fitconnect.api.auth.OAuthService;
+import fitconnect.api.auth.OAuthToken;
+import fitconnect.api.crypto.JWECryptoService;
+
+public class SubmissionSender implements Sender {
+
+    private final OAuthService authService;
+    private final JWECryptoService cryptoService;
+
+    public SubmissionSender(final OAuthService authService, JWECryptoService cryptoService){
+        this.authService = authService;
+        this.cryptoService = cryptoService;
+    }
+
+    @Override
+    public OAuthToken retrieveAuthenticationToken(String clientId, String clientSecret, String... scope) {
+        return authService.authenticate(clientId, clientSecret, scope).orElseThrow();
+    }
+
+    @Override
+    public String encryptData(RSAKey publicKey, String unencryptedData) {
+        return cryptoService.encryptString(publicKey, unencryptedData);
+    }
+
+    @Override
+    public String encryptAttachment(RSAKey publicKey, byte[] unencryptedAttachment) {
+        return cryptoService.encryptBytes(publicKey, unencryptedAttachment);
+    }
+
+}
diff --git a/client/src/main/java/fitconnect/client/impl/crypto/FitCoCryptoService.java b/client/src/main/java/fitconnect/client/impl/crypto/FitCoCryptoService.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d03aa5f72b04314056bcc92a2d9ffb8079681ad
--- /dev/null
+++ b/client/src/main/java/fitconnect/client/impl/crypto/FitCoCryptoService.java
@@ -0,0 +1,110 @@
+package fitconnect.client.impl.crypto;
+
+import com.nimbusds.jose.*;
+import com.nimbusds.jose.crypto.RSADecrypter;
+import com.nimbusds.jose.crypto.RSAEncrypter;
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.crypto.JWECryptoService;
+import fitconnect.api.problems.DecryptionProblem;
+import fitconnect.api.problems.EncryptionProblem;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPublicKey;
+import java.text.ParseException;
+
+public class FitCoCryptoService implements JWECryptoService {
+
+    public static final JWEAlgorithm ALGORITHM = JWEAlgorithm.RSA_OAEP_256;
+    public static final EncryptionMethod ENCRYPTION_METHOD = EncryptionMethod.A256GCM;
+
+    @Override
+    public String encryptString(RSAKey publicKey, String data) throws EncryptionProblem {
+        final Payload payload = getPayloadString(data);
+        return encrypt(publicKey, payload);
+    }
+
+    @Override
+    public String decryptString(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decrypt(privateKey, encryptedData).toString();
+    }
+
+    @Override
+    public String encryptBytes(RSAKey publicKey, byte[] bytes) throws EncryptionProblem {
+        final Payload payload = getPayloadBytes(bytes);
+        return encrypt(publicKey, payload);
+    }
+
+    @Override
+    public byte[] decryptBytes(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decrypt(privateKey, encryptedData).toBytes();
+    }
+
+    private String encrypt(RSAKey publicKey, Payload payload) throws EncryptionProblem {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+            keyGenerator.init(ENCRYPTION_METHOD.cekBitLength());
+            final SecretKey cek = keyGenerator.generateKey();
+            final String keyID = getIdFromPublicKey(publicKey);
+            return encryptPayload(publicKey,payload, cek, keyID);
+        } catch (NoSuchAlgorithmException | JOSEException e) {
+            throw new EncryptionProblem(e.getMessage());
+        }
+    }
+
+    private Payload decrypt(RSAKey privateKey, String encData) throws DecryptionProblem {
+        try {
+            final JWEObject jwe = JWEObject.parse(encData);
+            jwe.decrypt(new RSADecrypter(privateKey));
+            return jwe.getPayload();
+        } catch (ParseException | JOSEException e) {
+            throw new DecryptionProblem(e.getMessage());
+        }
+    }
+
+    private JWEObject getJWEObject(String keyID, Payload payload) {
+        return new JWEObject(getJWEHeader(keyID), payload);
+    }
+
+    private JWEHeader getJWEHeader(String keyID) {
+        return new JWEHeader.Builder(ALGORITHM, ENCRYPTION_METHOD)
+                .compressionAlgorithm(CompressionAlgorithm.DEF)
+                .contentType("application/json")
+                .keyID(keyID)
+                .build();
+    }
+
+    private RSAEncrypter getEncrypter(RSAPublicKey publicKey, SecretKey cek) {
+        return new RSAEncrypter(publicKey, cek);
+    }
+
+    private Payload getPayloadString(String data) {
+        return new Payload(data);
+    }
+
+    private Payload getPayloadBytes(byte[] bytes) {
+        return new Payload(bytes);
+    }
+
+    private String encryptPayload(RSAKey publicKey, Payload payload, SecretKey cek, String keyID) throws JOSEException {
+        JWEObject jwe = getJWEObject(keyID, payload);
+        jwe.encrypt(getEncrypter(publicKey.toRSAPublicKey(), cek));
+        checkIfJWEObjectIsEncrypted(jwe);
+        return jwe.serialize();
+    }
+
+    private void checkIfJWEObjectIsEncrypted(JWEObject jwe) {
+        if (!jwe.getState().equals(JWEObject.State.ENCRYPTED)) {
+            throw new EncryptionProblem("JWE object is not encrypted");
+        }
+    }
+
+    private String getIdFromPublicKey(RSAKey publicKey) {
+        final String keyID = publicKey.getKeyID();
+        if (keyID == null || keyID.isEmpty()) {
+            throw new EncryptionProblem("public key has no keyID");
+        }
+        return keyID;
+    }
+}
diff --git a/client/src/test/java/fitconnect/client/crypto/JWECryptoServiceTest.java b/client/src/test/java/fitconnect/client/crypto/JWECryptoServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..191cd1103bb61505250cb18c4ac2c982a1e031c1
--- /dev/null
+++ b/client/src/test/java/fitconnect/client/crypto/JWECryptoServiceTest.java
@@ -0,0 +1,56 @@
+package fitconnect.client.crypto;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
+import fitconnect.client.impl.crypto.FitCoCryptoService;
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JWECryptoServiceTest {
+
+    final fitconnect.api.crypto.JWECryptoService underTest = new FitCoCryptoService();
+
+    @Test
+    void encryptData() throws JOSEException {
+
+        // Given
+        final RSAKey privateKey = generateRsaKey(4096);
+        final RSAKey publicKey = privateKey.toPublicJWK();
+
+        // When
+        String encryptedData = underTest.encryptString(publicKey, "some foo");
+
+        // Then
+        assertNotNull(encryptedData);
+        assertNotEquals("some foo", encryptedData);
+    }
+
+    @Test
+    void decryptData() throws JOSEException {
+
+        // Given
+        final RSAKey privateKey = generateRsaKey(4096);
+        final RSAKey publicKey = privateKey.toPublicJWK();
+        String encryptedData = underTest.encryptString(publicKey, "some foo");
+
+        // When
+        String decrypted = underTest.decryptString(privateKey, encryptedData);
+
+        // Then
+        assertNotNull(decrypted);
+        assertEquals("some foo", decrypted);
+    }
+
+    public static RSAKey generateRsaKey(int size) throws JOSEException {
+        return new RSAKeyGenerator(size)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID(UUID.randomUUID().toString())
+                .generate();
+    }
+
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2578a5c4de3bd72568fc1a6a443615812a2c6c49..e32292b0c43ada586d53cda2853d224e7c31c4f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,17 @@
                 <artifactId>guava</artifactId>
                 <version>31.1-jre</version>
             </dependency>
+            <dependency>
+                <groupId>com.nimbusds</groupId>
+                <artifactId>nimbus-jose-jwt</artifactId>
+                <version>9.19</version>
+            </dependency>
+            <dependency>
+                <groupId>org.zalando</groupId>
+                <artifactId>problem</artifactId>
+                <version>0.27.1</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.junit.jupiter</groupId>
                 <artifactId>junit-jupiter</artifactId>
@@ -60,4 +71,18 @@
         </dependencies>
     </dependencyManagement>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>17</source>
+                    <target>17</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
 </project>
\ No newline at end of file