From 8394572707e6f6644562af3cb2127149585c4940 Mon Sep 17 00:00:00 2001
From: Martin Vogel <martin.vogel@sinc.de>
Date: Wed, 8 Jun 2022 14:35:32 +0200
Subject: [PATCH] #414 Separate encryption and decryption to different
 interfaces so that sender and subscriber only have to implement the details
 they actually need

---
 api/src/main/java/fitconnect/api/Sender.java  | 36 --------------
 .../main/java/fitconnect/api/Subscriber.java  | 48 -------------------
 .../fitconnect/api/auth/OAuthService.java     |  8 ++++
 ...ptoService.java => DecryptionService.java} | 25 +---------
 .../api/crypto/EncryptionService.java         | 31 ++++++++++++
 .../fitconnect/api/problems/AuthProblem.java  | 19 ++++++++
 .../de/fitconnect/client/ClientBuilder.java   | 10 ++--
 .../de/fitconnect/client/ClientFactory.java   | 33 +++++++++++++
 .../java/de/fitconnect/client/TestRunner.java | 10 ++--
 .../fitconnect/impl/SubmissionSender.java     | 30 +++++++-----
 .../fitconnect/impl/SubmissionSubscriber.java | 39 +++++++++++++++
 ...oCryptoService.java => CryptoService.java} | 38 ++-------------
 .../impl/crypto/JWEDecryptionService.java     | 18 +++++++
 .../impl/crypto/JWEEncryptionService.java     | 20 ++++++++
 .../impl/auth/OAuthTokenIntegrationTest.java  | 14 +++---
 .../impl/crypto/JWECryptoServiceTest.java     | 13 ++---
 16 files changed, 217 insertions(+), 175 deletions(-)
 delete mode 100644 api/src/main/java/fitconnect/api/Sender.java
 delete mode 100644 api/src/main/java/fitconnect/api/Subscriber.java
 rename api/src/main/java/fitconnect/api/crypto/{JWECryptoService.java => DecryptionService.java} (52%)
 create mode 100644 api/src/main/java/fitconnect/api/crypto/EncryptionService.java
 create mode 100644 api/src/main/java/fitconnect/api/problems/AuthProblem.java
 create mode 100644 client/src/main/java/de/fitconnect/client/ClientFactory.java
 create mode 100644 impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java
 rename impl/src/main/java/fitconnect/impl/crypto/{FitCoCryptoService.java => CryptoService.java} (68%)
 create mode 100644 impl/src/main/java/fitconnect/impl/crypto/JWEDecryptionService.java
 create mode 100644 impl/src/main/java/fitconnect/impl/crypto/JWEEncryptionService.java

diff --git a/api/src/main/java/fitconnect/api/Sender.java b/api/src/main/java/fitconnect/api/Sender.java
deleted file mode 100644
index 0e76e0a38..000000000
--- a/api/src/main/java/fitconnect/api/Sender.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package fitconnect.api;
-
-import com.nimbusds.jose.jwk.RSAKey;
-import fitconnect.api.auth.OAuthToken;
-
-/**
- * A technical system that creates a submission via the Submission API.
- */
-public interface Sender {
-
-    /**
-     * Authenticates the sender against the FIT-Co API and retrieves an authentication token
-     *
-     * @param clientId - a unique identifier within the FIT-Co platform environment
-     * @param clientSecret - a secret that is only known by the application and the OAuth server
-     * @param scope - OAuth scope(s) that determines if a submission is accepted by the client
-     * @return {@link OAuthToken} that holds the access-token
-     */
-    OAuthToken retrieveAuthenticationToken(final String clientId, final String clientSecret, String... scope);
-
-    /**
-     * Encrypts the submission data with JWE.
-     *
-     * @param unencryptedData - unencrypted JSON or XML data as string
-     * @return encrypted JSON or XML data as string
-     */
-     String encryptData(RSAKey publicKey, String unencryptedData);
-
-    /**
-     * Encrypts a submission attachment with JWE.
-     *
-     * @param unencryptedAttachment - unencrypted bytes of the attachment
-     * @return encrypted JWE string serialization of the attachment
-     */
-    String encryptAttachment(RSAKey publicKey, byte[] unencryptedAttachment);
-}
diff --git a/api/src/main/java/fitconnect/api/Subscriber.java b/api/src/main/java/fitconnect/api/Subscriber.java
deleted file mode 100644
index 8e7393da0..000000000
--- a/api/src/main/java/fitconnect/api/Subscriber.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package fitconnect.api;
-
-import fitconnect.api.auth.OAuthToken;
-import fitconnect.api.data.Data;
-import fitconnect.api.validation.ValidationResult;
-
-import java.io.ByteArrayInputStream;
-
-/**
- * The technical system that accepts submissions on the administration side.
- */
-public interface Subscriber {
-
-    /**
-     * Authenticates the sender against the FitCo API and retrieves an authentication token
-     * @param clientId -
-     * @param clientSecret -
-     * @return
-     */
-    OAuthToken retrieveAuthenticationToken(final String clientId, final String clientSecret);
-
-    /**
-     * Decrypts the subscribed data with JWE.
-     *
-     * @param encryptedData - encrypted JSON or XML data
-     * @return decrypted JSON or XML data
-     */
-    Data decryptData(final Data encryptedData);
-
-    /**
-     * Encrypts the submission attachment with JWE.
-     *
-     * @param unencryptedAttachmentBinary - the unencrypted binary data of the attachment
-     * @return the encrypted binary of the attachment
-     */
-    ByteArrayInputStream decryptAttachment(final ByteArrayInputStream unencryptedAttachmentBinary);
-
-    /**
-     * Validates metadata against a given json-schema
-     *
-     * @param attachment - the unencrypted binary data of the attachment
-     * @param jsonSchema - the schema the metadata is validated with
-     * @return A {@link ValidationResult} that informs about the validation and potential errors
-     */
-    ValidationResult validateMetadata(byte[] attachment, String jsonSchema);
-
-
-}
diff --git a/api/src/main/java/fitconnect/api/auth/OAuthService.java b/api/src/main/java/fitconnect/api/auth/OAuthService.java
index 738969c92..397d4fe92 100644
--- a/api/src/main/java/fitconnect/api/auth/OAuthService.java
+++ b/api/src/main/java/fitconnect/api/auth/OAuthService.java
@@ -4,5 +4,13 @@ import java.util.Optional;
 
 public interface OAuthService {
 
+    /**
+     * Authenticates the sender against the FIT-Co API and retrieves an authentication token
+     *
+     * @param clientId - a unique identifier within the FIT-Co platform environment
+     * @param clientSecret - a secret that is only known by the application and the OAuth server
+     * @param scope - OAuth scope(s) that determines if a submission is accepted by the client
+     * @return {@link OAuthToken} that holds the access-token
+     */
     Optional<OAuthToken> authenticate(String clientId, String clientSecret, String... scope);
 }
diff --git a/api/src/main/java/fitconnect/api/crypto/JWECryptoService.java b/api/src/main/java/fitconnect/api/crypto/DecryptionService.java
similarity index 52%
rename from api/src/main/java/fitconnect/api/crypto/JWECryptoService.java
rename to api/src/main/java/fitconnect/api/crypto/DecryptionService.java
index c23d3aebd..b87046708 100644
--- a/api/src/main/java/fitconnect/api/crypto/JWECryptoService.java
+++ b/api/src/main/java/fitconnect/api/crypto/DecryptionService.java
@@ -2,33 +2,12 @@ package fitconnect.api.crypto;
 
 import com.nimbusds.jose.jwk.RSAKey;
 import fitconnect.api.problems.DecryptionProblem;
-import fitconnect.api.problems.EncryptionProblem;
 
 /**
- * A service that allows to encrypt and decrypt data and attachments of a submission
+ * A service that allows to encrypt data and attachments of a submission
  * via <a href="https://datatracker.ietf.org/doc/html/rfc7516">JSON-Web-Encryption</a>
  */
-public interface JWECryptoService {
-
-    /**
-     * JWE encrypts a given string payload with the public key
-     *
-     * @param publicKey RSA public key the payload is encrypted with
-     * @param data json or xml data that should be encrypted
-     * @return a string serialization of the encrypted JWE object
-     * @throws EncryptionProblem if the payload cannot be encrypted or there was an issue with the key
-     */
-    String encryptString(final RSAKey publicKey, final String data) throws EncryptionProblem;
-
-    /**
-     * JWE encrypts a given byte[] payload with the public key
-     *
-     * @param publicKey RSA public key the payload is encrypted with
-     * @param bytes byte[] of the data that should be encrypted
-     * @return a string serialization of the encrypted JWE object
-     * @throws EncryptionProblem if the payload cannot be encrypted or there was an issue with the key
-     */
-    String encryptBytes(RSAKey publicKey, byte[] bytes) throws EncryptionProblem;
+public interface DecryptionService {
 
     /**
      * Decrypts a JWE encrypted string with the given private key
diff --git a/api/src/main/java/fitconnect/api/crypto/EncryptionService.java b/api/src/main/java/fitconnect/api/crypto/EncryptionService.java
new file mode 100644
index 000000000..d5def031c
--- /dev/null
+++ b/api/src/main/java/fitconnect/api/crypto/EncryptionService.java
@@ -0,0 +1,31 @@
+package fitconnect.api.crypto;
+
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.problems.EncryptionProblem;
+
+/**
+ * A service that allows to decrypt data and attachments of a submission
+ * via <a href="https://datatracker.ietf.org/doc/html/rfc7516">JSON-Web-Encryption</a>
+ */
+public interface EncryptionService {
+
+    /**
+     * JWE encrypts a given string payload with the public key
+     *
+     * @param publicKey RSA public key the payload is encrypted with
+     * @param data json or xml data that should be encrypted
+     * @return a string serialization of the encrypted JWE object
+     * @throws EncryptionProblem if the payload cannot be encrypted or there was an issue with the key
+     */
+    String encryptString(final RSAKey publicKey, final String data) throws EncryptionProblem;
+
+    /**
+     * JWE encrypts a given byte[] payload with the public key
+     *
+     * @param publicKey RSA public key the payload is encrypted with
+     * @param bytes byte[] of the data that should be encrypted
+     * @return a string serialization of the encrypted JWE object
+     * @throws EncryptionProblem if the payload cannot be encrypted or there was an issue with the key
+     */
+    String encryptBytes(RSAKey publicKey, byte[] bytes) throws EncryptionProblem;
+}
diff --git a/api/src/main/java/fitconnect/api/problems/AuthProblem.java b/api/src/main/java/fitconnect/api/problems/AuthProblem.java
new file mode 100644
index 000000000..8439b8801
--- /dev/null
+++ b/api/src/main/java/fitconnect/api/problems/AuthProblem.java
@@ -0,0 +1,19 @@
+package fitconnect.api.problems;
+
+import org.zalando.problem.Status;
+
+public class AuthProblem extends FitConnectProblem {
+
+    private static final long serialVersionUID = 1L;
+
+    public AuthProblem(String issue) {
+        super(
+                makeProblemURI("invalid-jwe-content"),
+                "Invalid JWE Content",
+                Status.BAD_REQUEST,
+                "There was a problem parsing the JWE",
+                null,
+                issue
+        );
+    }
+}
diff --git a/client/src/main/java/de/fitconnect/client/ClientBuilder.java b/client/src/main/java/de/fitconnect/client/ClientBuilder.java
index 65ed0661e..f1e79b80b 100644
--- a/client/src/main/java/de/fitconnect/client/ClientBuilder.java
+++ b/client/src/main/java/de/fitconnect/client/ClientBuilder.java
@@ -1,6 +1,5 @@
 package de.fitconnect.client;
 
-import fitconnect.api.Sender;
 import fitconnect.api.auth.OAuthService;
 import fitconnect.api.auth.OAuthToken;
 import fitconnect.api.logger.SdkLogger;
@@ -8,6 +7,7 @@ import fitconnect.impl.auth.FitCoAuthService;
 import fitconnect.impl.SubmissionSender;
 
 import java.net.http.HttpClient;
+import java.util.Optional;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -18,9 +18,9 @@ public class ClientBuilder {
     private static final String TOKEN_URL = "https://auth-testing.fit-connect.fitko.dev/token";
 
     private OAuthService authService;
-    private Sender sender;
+    private SubmissionSender sender;
 
-    private OAuthToken token;
+    private Optional<OAuthToken> token;
 
     // TODO use DI Container (Guice or Spring)
     public ClientBuilder(){
@@ -29,13 +29,13 @@ public class ClientBuilder {
     }
 
     public ClientBuilder authenticate(final String clientId, final String clientSecret){
-        this.token = sender.retrieveAuthenticationToken(clientId, clientSecret, "");
+        this.token = sender.authenticate(clientId, clientSecret, "");
         return this;
     }
 
     public ClientBuilder printAccessToken(){
         if(token != null){
-            logger.log(Level.INFO, token.access_token());
+            logger.log(Level.INFO, token.get().access_token());
         }else{
             logger.log(Level.INFO, "please authenticate first");
         }
diff --git a/client/src/main/java/de/fitconnect/client/ClientFactory.java b/client/src/main/java/de/fitconnect/client/ClientFactory.java
new file mode 100644
index 000000000..d887591b7
--- /dev/null
+++ b/client/src/main/java/de/fitconnect/client/ClientFactory.java
@@ -0,0 +1,33 @@
+package de.fitconnect.client;
+
+import fitconnect.api.auth.OAuthService;
+import fitconnect.api.crypto.DecryptionService;
+import fitconnect.api.crypto.EncryptionService;
+import fitconnect.impl.SubmissionSender;
+import fitconnect.impl.SubmissionSubscriber;
+import fitconnect.impl.auth.FitCoAuthService;
+import fitconnect.impl.crypto.JWEDecryptionService;
+import fitconnect.impl.crypto.JWEEncryptionService;
+
+import java.net.http.HttpClient;
+
+public class ClientFactory {
+
+    private static final String TOKEN_URL = "https://auth-testing.fit-connect.fitko.dev/token";
+
+    public static SubmissionSender submissionSender(){
+        final OAuthService authService = getAuthService();
+        final EncryptionService encryptionService = new JWEEncryptionService();
+        return new SubmissionSender(authService, encryptionService);
+    }
+
+    public static SubmissionSubscriber submissionSubscriber(){
+        final OAuthService authService = getAuthService();
+        final DecryptionService decryptionService = new JWEDecryptionService();
+        return new SubmissionSubscriber(authService, decryptionService);
+    }
+
+    private static FitCoAuthService getAuthService() {
+        return new FitCoAuthService(HttpClient.newHttpClient(), TOKEN_URL);
+    }
+}
diff --git a/client/src/main/java/de/fitconnect/client/TestRunner.java b/client/src/main/java/de/fitconnect/client/TestRunner.java
index ebf79e385..5a4c4876f 100644
--- a/client/src/main/java/de/fitconnect/client/TestRunner.java
+++ b/client/src/main/java/de/fitconnect/client/TestRunner.java
@@ -1,11 +1,13 @@
 package de.fitconnect.client;
 
+import fitconnect.impl.SubmissionSubscriber;
+
 public class TestRunner {
 
     public static void main(String[] args) {
-        ClientBuilder client = new ClientBuilder();
-        client
-                .authenticate("781f6213-0f0f-4a79-9372-e7187ffda98b","PnzR8Vbmhpv_VwTkT34wponqXWK8WBm-LADlryYdV4o")
-                .printAccessToken();
+
+        SubmissionSubscriber submissionSubscriber = ClientFactory.submissionSubscriber();
+        submissionSubscriber.authenticate("781f6213-0f0f-4a79-9372-e7187ffda98b","PnzR8Vbmhpv_VwTkT34wponqXWK8WBm-LADlryYdV4o");
+
     }
 }
diff --git a/impl/src/main/java/fitconnect/impl/SubmissionSender.java b/impl/src/main/java/fitconnect/impl/SubmissionSender.java
index 3fa22a8f2..36278545d 100644
--- a/impl/src/main/java/fitconnect/impl/SubmissionSender.java
+++ b/impl/src/main/java/fitconnect/impl/SubmissionSender.java
@@ -1,34 +1,38 @@
 package fitconnect.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;
+import fitconnect.api.crypto.EncryptionService;
+import fitconnect.api.problems.EncryptionProblem;
 
-public class SubmissionSender implements Sender {
+import java.util.Optional;
+
+/**
+ * A technical system that creates a submission via the FIT-Co Submission API.
+ */
+public class SubmissionSender implements OAuthService, EncryptionService {
 
     private final OAuthService authService;
-    private final JWECryptoService cryptoService;
+    private final EncryptionService encryptionService;
 
-    public SubmissionSender(final OAuthService authService, JWECryptoService cryptoService){
+    public SubmissionSender(final OAuthService authService, final EncryptionService encryptionService){
         this.authService = authService;
-        this.cryptoService = cryptoService;
+        this.encryptionService = encryptionService;
     }
 
     @Override
-    public OAuthToken retrieveAuthenticationToken(String clientId, String clientSecret, String... scope) {
-        return authService.authenticate(clientId, clientSecret, scope).orElseThrow();
+    public Optional<OAuthToken> authenticate(String clientId, String clientSecret, String... scope) {
+        return authService.authenticate(clientId, clientSecret, scope);
     }
 
     @Override
-    public String encryptData(RSAKey publicKey, String unencryptedData) {
-        return cryptoService.encryptString(publicKey, unencryptedData);
+    public String encryptString(RSAKey publicKey, String unencryptedData) throws EncryptionProblem {
+        return encryptionService.encryptString(publicKey, unencryptedData);
     }
 
     @Override
-    public String encryptAttachment(RSAKey publicKey, byte[] unencryptedAttachment) {
-        return cryptoService.encryptBytes(publicKey, unencryptedAttachment);
+    public String encryptBytes(RSAKey publicKey, byte[] unencryptedAttachment) throws EncryptionProblem {
+        return encryptionService.encryptBytes(publicKey, unencryptedAttachment);
     }
-
 }
diff --git a/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java b/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java
new file mode 100644
index 000000000..e4e1e2f43
--- /dev/null
+++ b/impl/src/main/java/fitconnect/impl/SubmissionSubscriber.java
@@ -0,0 +1,39 @@
+package fitconnect.impl;
+
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.auth.OAuthService;
+import fitconnect.api.auth.OAuthToken;
+import fitconnect.api.crypto.DecryptionService;
+import fitconnect.api.problems.DecryptionProblem;
+
+import java.util.Optional;
+
+/**
+ * The technical system that accepts submissions on the administration side.
+ */
+public class SubmissionSubscriber implements OAuthService, DecryptionService {
+
+    private final OAuthService authService;
+    private final DecryptionService decryptionService;
+
+    public SubmissionSubscriber(final OAuthService authService, final DecryptionService decryptionService){
+        this.authService = authService;
+        this.decryptionService = decryptionService;
+    }
+
+    @Override
+    public Optional<OAuthToken> authenticate(String clientId, String clientSecret, String... scope) {
+        return authService.authenticate(clientId, clientSecret, scope);
+    }
+
+    @Override
+    public String decryptString(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decryptionService.decryptString(privateKey, encryptedData);
+    }
+
+    @Override
+    public byte[] decryptBytes(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decryptionService.decryptBytes(privateKey, encryptedData);
+
+    }
+}
diff --git a/impl/src/main/java/fitconnect/impl/crypto/FitCoCryptoService.java b/impl/src/main/java/fitconnect/impl/crypto/CryptoService.java
similarity index 68%
rename from impl/src/main/java/fitconnect/impl/crypto/FitCoCryptoService.java
rename to impl/src/main/java/fitconnect/impl/crypto/CryptoService.java
index daa57a488..5fbfedaf1 100644
--- a/impl/src/main/java/fitconnect/impl/crypto/FitCoCryptoService.java
+++ b/impl/src/main/java/fitconnect/impl/crypto/CryptoService.java
@@ -4,7 +4,6 @@ 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;
 
@@ -14,34 +13,12 @@ import java.security.NoSuchAlgorithmException;
 import java.security.interfaces.RSAPublicKey;
 import java.text.ParseException;
 
-public class FitCoCryptoService implements JWECryptoService {
+public abstract class CryptoService {
 
     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 {
+    String encrypt(RSAKey publicKey, Payload payload) throws EncryptionProblem {
         try {
             KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
             keyGenerator.init(ENCRYPTION_METHOD.cekBitLength());
@@ -53,7 +30,7 @@ public class FitCoCryptoService implements JWECryptoService {
         }
     }
 
-    private Payload decrypt(RSAKey privateKey, String encData) throws DecryptionProblem {
+    Payload decrypt(RSAKey privateKey, String encData) throws DecryptionProblem {
         try {
             final JWEObject jwe = JWEObject.parse(encData);
             jwe.decrypt(new RSADecrypter(privateKey));
@@ -79,14 +56,6 @@ public class FitCoCryptoService implements JWECryptoService {
         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));
@@ -107,4 +76,5 @@ public class FitCoCryptoService implements JWECryptoService {
         }
         return keyID;
     }
+
 }
diff --git a/impl/src/main/java/fitconnect/impl/crypto/JWEDecryptionService.java b/impl/src/main/java/fitconnect/impl/crypto/JWEDecryptionService.java
new file mode 100644
index 000000000..bed3b8bb1
--- /dev/null
+++ b/impl/src/main/java/fitconnect/impl/crypto/JWEDecryptionService.java
@@ -0,0 +1,18 @@
+package fitconnect.impl.crypto;
+
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.crypto.DecryptionService;
+import fitconnect.api.problems.DecryptionProblem;
+
+public class JWEDecryptionService extends CryptoService implements DecryptionService {
+
+    @Override
+    public String decryptString(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decrypt(privateKey, encryptedData).toString();
+    }
+
+    @Override
+    public byte[] decryptBytes(RSAKey privateKey, String encryptedData) throws DecryptionProblem {
+        return decrypt(privateKey, encryptedData).toBytes();
+    }
+}
diff --git a/impl/src/main/java/fitconnect/impl/crypto/JWEEncryptionService.java b/impl/src/main/java/fitconnect/impl/crypto/JWEEncryptionService.java
new file mode 100644
index 000000000..6625063e2
--- /dev/null
+++ b/impl/src/main/java/fitconnect/impl/crypto/JWEEncryptionService.java
@@ -0,0 +1,20 @@
+package fitconnect.impl.crypto;
+
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.jwk.RSAKey;
+import fitconnect.api.problems.EncryptionProblem;
+
+public class JWEEncryptionService extends CryptoService implements fitconnect.api.crypto.EncryptionService {
+
+    @Override
+    public String encryptString(RSAKey publicKey, String data) throws EncryptionProblem {
+        final Payload payload = new Payload(data);
+        return encrypt(publicKey, payload);
+    }
+
+    @Override
+    public String encryptBytes(RSAKey publicKey, byte[] bytes) throws EncryptionProblem {
+        final Payload payload =  new Payload(bytes);;
+        return encrypt(publicKey, payload);
+    }
+}
diff --git a/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java b/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java
index 604d913bb..2e00e9f71 100644
--- a/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java
+++ b/impl/src/test/java/fitconnect/impl/auth/OAuthTokenIntegrationTest.java
@@ -1,11 +1,11 @@
 package fitconnect.impl.auth;
 
 import fitconnect.api.auth.OAuthToken;
-import fitconnect.impl.auth.FitCoAuthService;
 import fitconnect.impl.SubmissionSender;
 import org.junit.jupiter.api.Test;
 
 import java.net.http.HttpClient;
+import java.util.Optional;
 
 import static org.junit.jupiter.api.Assertions.*;
 
@@ -22,14 +22,16 @@ class OAuthTokenIntegrationTest {
 
         var httpClient = HttpClient.newHttpClient();
         var authService = new FitCoAuthService(httpClient, tokenUrl);
-        var sender = new SubmissionSender(authService, null);
+        final SubmissionSender sender = new SubmissionSender(authService, null);
 
         // When
-        OAuthToken token = sender.retrieveAuthenticationToken(clientId, secret, scope);
+        Optional<OAuthToken> token = sender.authenticate(clientId, secret, scope);
 
         // Then
-        assertNull(token.error());
-        assertNotNull(token.access_token());
-        assertEquals(1800, token.expires_in());
+
+        assertTrue(token.isPresent());
+        assertNull(token.get().error());
+        assertNotNull(token.get().access_token());
+        assertEquals(1800, token.get().expires_in());
     }
 }
\ No newline at end of file
diff --git a/impl/src/test/java/fitconnect/impl/crypto/JWECryptoServiceTest.java b/impl/src/test/java/fitconnect/impl/crypto/JWECryptoServiceTest.java
index 60a92b00a..74919dfca 100644
--- a/impl/src/test/java/fitconnect/impl/crypto/JWECryptoServiceTest.java
+++ b/impl/src/test/java/fitconnect/impl/crypto/JWECryptoServiceTest.java
@@ -4,8 +4,8 @@ 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.api.crypto.JWECryptoService;
-import fitconnect.impl.crypto.FitCoCryptoService;
+import fitconnect.api.crypto.DecryptionService;
+import fitconnect.api.crypto.EncryptionService;
 import org.junit.jupiter.api.Test;
 
 import java.util.UUID;
@@ -14,7 +14,8 @@ import static org.junit.jupiter.api.Assertions.*;
 
 class JWECryptoServiceTest {
 
-    final JWECryptoService underTest = new FitCoCryptoService();
+    final EncryptionService encryptionUnderTest = new JWEEncryptionService();
+    final DecryptionService decryptionUnderTest = new JWEDecryptionService();
 
     @Test
     void encryptData() throws JOSEException {
@@ -24,7 +25,7 @@ class JWECryptoServiceTest {
         final RSAKey publicKey = privateKey.toPublicJWK();
 
         // When
-        String encryptedData = underTest.encryptString(publicKey, "some foo");
+        String encryptedData = encryptionUnderTest.encryptString(publicKey, "some foo");
 
         // Then
         assertNotNull(encryptedData);
@@ -37,10 +38,10 @@ class JWECryptoServiceTest {
         // Given
         final RSAKey privateKey = generateRsaKey(4096);
         final RSAKey publicKey = privateKey.toPublicJWK();
-        String encryptedData = underTest.encryptString(publicKey, "some foo");
+        String encryptedData = encryptionUnderTest.encryptString(publicKey, "some foo");
 
         // When
-        String decrypted = underTest.decryptString(privateKey, encryptedData);
+        String decrypted = decryptionUnderTest.decryptString(privateKey, encryptedData);
 
         // Then
         assertNotNull(decrypted);
-- 
GitLab