Skip to content

Commit

Permalink
chore: add aggregate error
Browse files Browse the repository at this point in the history
  • Loading branch information
TheUnderScorer committed Jan 26, 2024
1 parent f80e467 commit a1afa5c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 17 deletions.
54 changes: 41 additions & 13 deletions src/main/java/com/fingerprint/Sealed.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fingerprint.model.EventResponse;
import com.fingerprint.sdk.ApiClient;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Logger;
import java.util.List;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

public class Sealed {
private static final Logger log = Logger.getLogger(ApiClient.class.getName());

public enum DecryptionAlgorithm {
AES_256_GCM
}
Expand All @@ -32,47 +30,77 @@ public DecryptionKey(byte[] key, DecryptionAlgorithm algorithm) {
}
}

public static class UnsealAggregateException extends Exception {
private final List<UnsealException> unsealExceptions = new ArrayList<>();

public UnsealAggregateException() {
super("Failed to unseal with all decryption keys");
}

public void addUnsealException(UnsealException exception) {
unsealExceptions.add(exception);
}

public List<UnsealException> getUnsealExceptions() {
return unsealExceptions;
}
}

public static class UnsealException extends Exception {
public final DecryptionKey decryptionKey;

public final Exception exception;

public UnsealException(String message, DecryptionKey decryptionKey, Exception exception) {
super(message);
this.decryptionKey = decryptionKey;
this.exception = exception;
}
}
private static final byte[] SEAL_HEADER = new byte[]{(byte) 0x9E, (byte) 0x85, (byte) 0xDC, (byte) 0xED};
private static final int NONCE_LENGTH = 12;
private static final int AUTH_TAG_LENGTH = 16;

public static byte[] unseal(byte[] sealed, DecryptionKey[] keys) throws IllegalArgumentException {
public static byte[] unseal(byte[] sealed, DecryptionKey[] keys) throws IllegalArgumentException, UnsealAggregateException {
if (!Arrays.equals(Arrays.copyOf(sealed, SEAL_HEADER.length), SEAL_HEADER)) {
throw new IllegalArgumentException("Invalid sealed data header");
}

int index = 0;
UnsealAggregateException aggregateException = new UnsealAggregateException();

for (DecryptionKey key : keys) {
switch (key.algorithm) {
case AES_256_GCM:
try {
return decryptAes256Gcm(Arrays.copyOfRange(sealed, SEAL_HEADER.length, sealed.length), key.key);
} catch (Exception exception) {
log.warning(String.format("Failed to decrypt with key: %d error: %s", index, exception.getMessage()));
aggregateException.addUnsealException(
new UnsealException(
"Failed to decrypt",
key,
exception
)
);
}

break;

default:
throw new IllegalArgumentException("Invalid decryption algorithm");
}

index++;
}

throw new IllegalArgumentException("Invalid decryption keys");
throw aggregateException;
}

/**
* decrypts the sealed response with the provided keys.
*
* @param sealed Base64 encoded sealed data
* @param keys Decryption keys. The SDK will try to decrypt the result with each key until it succeeds.
* @param keys Decryption keys. The SDK will try to decrypt the result with each key until it succeeds.
* @return EventResponse
* @throws Exception if the sealed data is invalid or if the decryption keys are invalid
*/
public static EventResponse unsealEventResponse(byte[] sealed, DecryptionKey[] keys) throws Exception {
public static EventResponse unsealEventResponse(byte[] sealed, DecryptionKey[] keys) throws IllegalArgumentException, UnsealAggregateException, IOException {
byte[] unsealed = unseal(sealed, keys);

ObjectMapper mapper = ObjectMapperUtil.getObjectMapper();
Expand Down
6 changes: 2 additions & 4 deletions src/test/java/com/fingerprint/SealedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

import java.util.Base64;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SealedTest {
Expand Down Expand Up @@ -68,7 +67,7 @@ public void unsealEventResponseWithInvalidHeaderTest() throws Exception {
public void unsealEventResponseWithInvalidKeysTest() throws Exception {
byte[] sealedResult = Base64.getDecoder().decode("noXc7SXO+mqeAGrvBMgObi/S0fXTpP3zupk8qFqsO/1zdtWCD169iLA3VkkZh9ICHpZ0oWRzqG0M9/TnCeKFohgBLqDp6O0zEfXOv6i5q++aucItznQdLwrKLP+O0blfb4dWVI8/aSbd4ELAZuJJxj9bCoVZ1vk+ShbUXCRZTD30OIEAr3eiG9aw00y1UZIqMgX6CkFlU9L9OnKLsNsyomPIaRHTmgVTI5kNhrnVNyNsnzt9rY7fUD52DQxJILVPrUJ1Q+qW7VyNslzGYBPG0DyYlKbRAomKJDQIkdj/Uwa6bhSTq4XYNVvbk5AJ/dGwvsVdOnkMT2Ipd67KwbKfw5bqQj/cw6bj8Cp2FD4Dy4Ud4daBpPRsCyxBM2jOjVz1B/lAyrOp8BweXOXYugwdPyEn38MBZ5oL4D38jIwR/QiVnMHpERh93jtgwh9Abza6i4/zZaDAbPhtZLXSM5ztdctv8bAb63CppLU541Kf4OaLO3QLvfLRXK2n8bwEwzVAqQ22dyzt6/vPiRbZ5akh8JB6QFXG0QJF9DejsIspKF3JvOKjG2edmC9o+GfL3hwDBiihYXCGY9lElZICAdt+7rZm5UxMx7STrVKy81xcvfaIp1BwGh/HyMsJnkE8IczzRFpLlHGYuNDxdLoBjiifrmHvOCUDcV8UvhSV+UAZtAVejdNGo5G/bz0NF21HUO4pVRPu6RqZIs/aX4hlm6iO/0Ru00ct8pfadUIgRcephTuFC2fHyZxNBC6NApRtLSNLfzYTTo/uSjgcu6rLWiNo5G7yfrM45RXjalFEFzk75Z/fu9lCJJa5uLFgDNKlU+IaFjArfXJCll3apbZp4/LNKiU35ZlB7ZmjDTrji1wLep8iRVVEGht/DW00MTok7Zn7Fv+MlxgWmbZB3BuezwTmXb/fNw==");

Exception thrown = assertThrows(Exception.class, () -> Sealed.unsealEventResponse(
assertThrows(Sealed.UnsealAggregateException.class, () -> Sealed.unsealEventResponse(
sealedResult,
new Sealed.DecryptionKey[]{
new Sealed.DecryptionKey(
Expand All @@ -87,6 +86,5 @@ public void unsealEventResponseWithInvalidKeysTest() throws Exception {
}
));

assertEquals("Invalid decryption keys", thrown.getMessage());
}
}

0 comments on commit a1afa5c

Please sign in to comment.