From d9ce83c772545cdef45349dbdcedba35c4b69a88 Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Sat, 20 Jul 2024 15:12:10 -0400 Subject: [PATCH 01/16] updated policy binding format --- sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java | 9 ++++++++- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 4 +++- .../test/java/io/opentdf/platform/sdk/ManifestTest.java | 7 +++++-- .../test/java/io/opentdf/platform/sdk/TDFWriterTest.java | 7 +++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index a8457493..208c7542 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -25,6 +25,11 @@ static public class IntegrityInformation { public int encryptedSegmentSizeDefault; public List segments; } + + static public class PolicyBinding { + public String alg; + public String hash; + } static public class KeyAccess { @SerializedName(value = "type") @@ -32,7 +37,7 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; - public String policyBinding; + public PolicyBinding policyBinding; public String encryptedMetadata; public String kid; } @@ -43,6 +48,8 @@ static public class Method { public Boolean IsStreamable; } + + static public class EncryptionInformation { @SerializedName(value = "type") public String keyAccessType; diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index aab8ea33..69aaae2c 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -191,7 +191,9 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { // Add policyBinding var hexBinding = Hex.encodeHexString(CryptoUtils.CalculateSHA256Hmac(symKey, base64PolicyObject.getBytes(StandardCharsets.UTF_8))); - keyAccess.policyBinding = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8)); + keyAccess.policyBinding = new Manifest.PolicyBinding(); + keyAccess.policyBinding.alg = "HS256"; + keyAccess.policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8));; // Wrap the key with kas public key AsymEncryption asymmetricEncrypt = new AsymEncryption(kasInfo.PublicKey); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 558cdacc..cf8ba40f 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -11,7 +11,7 @@ public class ManifestTest { @Test void testManifestMarshalAndUnMarshal() { - String kManifestJsonFromTDF = "{\n" + +String kManifestJsonFromTDF = "{\n" + " \"encryptionInformation\": {\n" + " \"integrityInformation\": {\n" + " \"encryptedSegmentSizeDefault\": 1048604,\n" + @@ -31,7 +31,10 @@ void testManifestMarshalAndUnMarshal() { " },\n" + " \"keyAccess\": [\n" + " {\n" + - " \"policyBinding\": \"YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA==\",\n" + + " \"policyBinding\": {\n" + + " \"alg\": \"HS256\",\n" + + " \"hash\": \"YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA==\"\n" + + " },\n" + " \"protocol\": \"kas\",\n" + " \"type\": \"wrapped\",\n" + " \"url\": \"http://localhost:65432/kas\",\n" + diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java index 663841bb..ad446bdb 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java @@ -16,7 +16,7 @@ public class TDFWriterTest { @Test void simpleTDFCreate() throws IOException { - String kManifestJsonFromTDF = "{\n" + +String kManifestJsonFromTDF = "{\n" + " \"encryptionInformation\": {\n" + " \"integrityInformation\": {\n" + " \"encryptedSegmentSizeDefault\": 1048604,\n" + @@ -36,7 +36,10 @@ void simpleTDFCreate() throws IOException { " },\n" + " \"keyAccess\": [\n" + " {\n" + - " \"policyBinding\": \"YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA==\",\n" + + " \"policyBinding\": {\n" + + " \"alg\": \"HS256\",\n" + + " \"hash\": \"YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA==\"\n" + + " },\n" + " \"protocol\": \"kas\",\n" + " \"type\": \"wrapped\",\n" + " \"url\": \"http://localhost:65432/kas\",\n" + From 48c5912c50607ca2c89b519239e1b587c1a303ef Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Mon, 22 Jul 2024 13:21:16 -0400 Subject: [PATCH 02/16] update manifest test --- sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index cf8ba40f..6d2b4785 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -73,7 +73,8 @@ void testManifestMarshalAndUnMarshal() { List keyAccess = manifest.encryptionInformation.keyAccessObj; assertEquals(keyAccess.get(0).keyType, "wrapped"); assertEquals(keyAccess.get(0).protocol, "kas"); - + assertEquals(keyAccess.get(0).policyBinding.alg, "HS256"); + assertEquals(keyAccess.get(0).policyBinding.hash, "YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA=="); assertEquals(manifest.encryptionInformation.method.algorithm, "AES-256-GCM"); assertEquals(manifest.encryptionInformation.integrityInformation.rootSignature.algorithm, "HS256"); assertEquals(manifest.encryptionInformation.integrityInformation.segmentHashAlg, "GMAC"); From fe943c349c7383e1443852e10c741aaf67c6b157 Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Mon, 22 Jul 2024 13:26:49 -0400 Subject: [PATCH 03/16] use const --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 69aaae2c..2082d654 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -192,7 +192,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { // Add policyBinding var hexBinding = Hex.encodeHexString(CryptoUtils.CalculateSHA256Hmac(symKey, base64PolicyObject.getBytes(StandardCharsets.UTF_8))); keyAccess.policyBinding = new Manifest.PolicyBinding(); - keyAccess.policyBinding.alg = "HS256"; + keyAccess.policyBinding.alg = kHmacIntegrityAlgorithm; keyAccess.policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8));; // Wrap the key with kas public key From 0d7de11ee87411f362cc5d71e95f0fbe987d658a Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Tue, 23 Jul 2024 16:05:41 -0400 Subject: [PATCH 04/16] test policy binding fix --- .../java/io/opentdf/platform/sdk/Manifest.java | 2 +- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index 208c7542..276d9cca 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -37,7 +37,7 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; - public PolicyBinding policyBinding; + public Object policyBinding; public String encryptedMetadata; public String kid; } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 2082d654..0b08aae6 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -68,6 +68,20 @@ public TDF() { private static final String kAssertionHash = "assertionHash"; private static final SecureRandom sRandom = new SecureRandom(); + + public class PolicyBindingDeserializer implements JsonDeserializer { + @Override + public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (json.isJsonObject()) { + return context.deserialize(json, PolicyBinding.class); + } else if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { + return json.getAsString(); + } else { + throw new JsonParseException("Unexpected type for policyBinding"); + } + } + } + gsonBuilder.registerTypeAdapter(Object.class, new PolicyBindingDeserializer()); private static final Gson gson = new GsonBuilder().create(); public static class DataSizeNotSupported extends RuntimeException { From f61e64648e372fed2c8e76ac5d4786bb5d536c03 Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Tue, 23 Jul 2024 16:28:12 -0400 Subject: [PATCH 05/16] maybe fix? --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 0b08aae6..c08d8b61 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -81,8 +81,9 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } } - gsonBuilder.registerTypeAdapter(Object.class, new PolicyBindingDeserializer()); - private static final Gson gson = new GsonBuilder().create(); + private static final Gson gson = new GsonBuilder(); + gson.registerTypeAdapter(Object.class, new PolicyBindingDeserializer()); + gson.create(); public static class DataSizeNotSupported extends RuntimeException { public DataSizeNotSupported(String errorMessage) { From 5e04c5ed13a6580d57c48e7f02ed50d0d1a8451f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 23 Jul 2024 22:35:47 +0200 Subject: [PATCH 06/16] get it to compile --- .../io/opentdf/platform/sdk/Manifest.java | 2 +- .../java/io/opentdf/platform/sdk/TDF.java | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index 276d9cca..208c7542 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -37,7 +37,7 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; - public Object policyBinding; + public PolicyBinding policyBinding; public String encryptedMetadata; public String kid; } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index c08d8b61..b4b2c6d9 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -3,6 +3,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; import com.nimbusds.jose.*; import com.nimbusds.jose.crypto.MACVerifier; import com.nimbusds.jose.crypto.RSASSAVerifier; @@ -26,6 +30,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Type; import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; import java.security.*; @@ -69,11 +74,11 @@ public TDF() { private static final SecureRandom sRandom = new SecureRandom(); - public class PolicyBindingDeserializer implements JsonDeserializer { + public static class PolicyBindingDeserializer implements JsonDeserializer { @Override public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (json.isJsonObject()) { - return context.deserialize(json, PolicyBinding.class); + return context.deserialize(json, Manifest.PolicyBinding.class); } else if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { return json.getAsString(); } else { @@ -81,9 +86,14 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } } - private static final Gson gson = new GsonBuilder(); - gson.registerTypeAdapter(Object.class, new PolicyBindingDeserializer()); - gson.create(); + + private static final Gson gson; + + static { + gson = new GsonBuilder() + .registerTypeAdapter(Object.class, new PolicyBindingDeserializer()) + .create(); + } public static class DataSizeNotSupported extends RuntimeException { public DataSizeNotSupported(String errorMessage) { From cfc55794bef21ea3d70e4ab1220064d8c18e8b34 Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Tue, 23 Jul 2024 16:46:26 -0400 Subject: [PATCH 07/16] trying again --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index c08d8b61..600da0a8 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -81,9 +81,9 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } } - private static final Gson gson = new GsonBuilder(); - gson.registerTypeAdapter(Object.class, new PolicyBindingDeserializer()); - gson.create(); + private static final Gson gson = new GsonBuilder() + .registerTypeAdapter(Object.class, new PolicyBindingDeserializer()) + .create(); public static class DataSizeNotSupported extends RuntimeException { public DataSizeNotSupported(String errorMessage) { From 9ac737567160941b7fbeeaa3912ad6cd14456a41 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 23 Jul 2024 22:56:19 +0200 Subject: [PATCH 08/16] missed the point --- sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java | 2 +- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 7 ++++--- .../test/java/io/opentdf/platform/sdk/ManifestTest.java | 6 ++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index 208c7542..276d9cca 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -37,7 +37,7 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; - public PolicyBinding policyBinding; + public Object policyBinding; public String encryptedMetadata; public String kid; } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index b4b2c6d9..e038a474 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -216,9 +216,10 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { // Add policyBinding var hexBinding = Hex.encodeHexString(CryptoUtils.CalculateSHA256Hmac(symKey, base64PolicyObject.getBytes(StandardCharsets.UTF_8))); - keyAccess.policyBinding = new Manifest.PolicyBinding(); - keyAccess.policyBinding.alg = kHmacIntegrityAlgorithm; - keyAccess.policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8));; + var policyBinding = new Manifest.PolicyBinding(); + policyBinding.alg = kHmacIntegrityAlgorithm; + policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8));; + keyAccess.policyBinding = policyBinding; // Wrap the key with kas public key AsymEncryption asymmetricEncrypt = new AsymEncryption(kasInfo.PublicKey); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 6d2b4785..91ce2477 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -73,8 +73,10 @@ void testManifestMarshalAndUnMarshal() { List keyAccess = manifest.encryptionInformation.keyAccessObj; assertEquals(keyAccess.get(0).keyType, "wrapped"); assertEquals(keyAccess.get(0).protocol, "kas"); - assertEquals(keyAccess.get(0).policyBinding.alg, "HS256"); - assertEquals(keyAccess.get(0).policyBinding.hash, "YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA=="); + assertEquals(keyAccess.get(0).policyBinding.getClass(), Manifest.PolicyBinding.class); + var policyBinding = (Manifest.PolicyBinding)keyAccess.get(0).policyBinding; + assertEquals(policyBinding.alg, "HS256"); + assertEquals(policyBinding.hash, "YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA=="); assertEquals(manifest.encryptionInformation.method.algorithm, "AES-256-GCM"); assertEquals(manifest.encryptionInformation.integrityInformation.rootSignature.algorithm, "HS256"); assertEquals(manifest.encryptionInformation.integrityInformation.segmentHashAlg, "GMAC"); From e85f971af11e7fa21e6c178e3b4ce02368263c65 Mon Sep 17 00:00:00 2001 From: Tyler Biscoe Date: Tue, 23 Jul 2024 17:03:51 -0400 Subject: [PATCH 09/16] stupid conflict --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index b49e6db0..3c772bc0 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -86,11 +86,7 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } } -<<<<<<< HEAD - private static final Gson gson = new GsonBuilder() - .registerTypeAdapter(Object.class, new PolicyBindingDeserializer()) - .create(); -======= + private static final Gson gson; @@ -99,7 +95,6 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon .registerTypeAdapter(Object.class, new PolicyBindingDeserializer()) .create(); } ->>>>>>> 9ac737567160941b7fbeeaa3912ad6cd14456a41 public static class DataSizeNotSupported extends RuntimeException { public DataSizeNotSupported(String errorMessage) { From 33c340798513a5ea7c9e134f4c9fafec3d5d3595 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 23 Jul 2024 23:07:45 +0200 Subject: [PATCH 10/16] use an attribute --- .../main/java/io/opentdf/platform/sdk/Manifest.java | 3 +++ sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 9 +-------- .../java/io/opentdf/platform/sdk/ManifestTest.java | 11 ++--------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index 276d9cca..09b0d7e1 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -1,5 +1,6 @@ package io.opentdf.platform.sdk; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; import java.util.List; @@ -37,7 +38,9 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; + @JsonAdapter(TDF.PolicyBindingDeserializer.class) public Object policyBinding; + public String encryptedMetadata; public String kid; } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index e038a474..7870c8ab 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -87,14 +87,7 @@ public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon } } - private static final Gson gson; - - static { - gson = new GsonBuilder() - .registerTypeAdapter(Object.class, new PolicyBindingDeserializer()) - .create(); - } - + private static final Gson gson = new Gson(); public static class DataSizeNotSupported extends RuntimeException { public DataSizeNotSupported(String errorMessage) { super(errorMessage); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 91ce2477..39d7e48c 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -58,9 +58,7 @@ void testManifestMarshalAndUnMarshal() { " }\n" + "}"; - GsonBuilder gsonBuilder = new GsonBuilder(); - Gson gson = gsonBuilder.setPrettyPrinting().create(); - Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); + Manifest manifest = new Gson().fromJson(kManifestJsonFromTDF, Manifest.class); // Test payload assertEquals(manifest.payload.url, "0.payload"); @@ -73,7 +71,7 @@ void testManifestMarshalAndUnMarshal() { List keyAccess = manifest.encryptionInformation.keyAccessObj; assertEquals(keyAccess.get(0).keyType, "wrapped"); assertEquals(keyAccess.get(0).protocol, "kas"); - assertEquals(keyAccess.get(0).policyBinding.getClass(), Manifest.PolicyBinding.class); + assertEquals(Manifest.PolicyBinding.class, keyAccess.get(0).policyBinding.getClass()); var policyBinding = (Manifest.PolicyBinding)keyAccess.get(0).policyBinding; assertEquals(policyBinding.alg, "HS256"); assertEquals(policyBinding.hash, "YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA=="); @@ -82,9 +80,6 @@ void testManifestMarshalAndUnMarshal() { assertEquals(manifest.encryptionInformation.integrityInformation.segmentHashAlg, "GMAC"); assertEquals(manifest.encryptionInformation.integrityInformation.segments.get(0).segmentSize, 1048576); - System.out.println(gson.toJson(manifest)); - - Manifest.Payload payload = new Manifest.Payload(); payload.protocol = "zip"; @@ -94,7 +89,5 @@ void testManifestMarshalAndUnMarshal() { Manifest newManifest = new Manifest(); newManifest.payload = payload; newManifest.encryptionInformation = encryptionInformation; - - System.out.println(gson.toJson(newManifest)); } } From 3a04a21b3e1318f69ffada0ec7d8f578ae3387ee Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 24 Jul 2024 09:11:46 +0200 Subject: [PATCH 11/16] you need to both serialize and deserialize --- .../io/opentdf/platform/sdk/Manifest.java | 144 +++++++++++++++++- .../java/io/opentdf/platform/sdk/TDF.java | 24 +-- .../io/opentdf/platform/sdk/ManifestTest.java | 17 +-- 3 files changed, 153 insertions(+), 32 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index 09b0d7e1..1b30818e 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -1,15 +1,66 @@ package io.opentdf.platform.sdk; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import java.lang.reflect.Type; import java.util.List; +import java.util.Objects; public class Manifest { + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Manifest manifest = (Manifest) o; + return Objects.equals(encryptionInformation, manifest.encryptionInformation) && Objects.equals(payload, manifest.payload) && Objects.equals(assertions, manifest.assertions); + } + + @Override + public int hashCode() { + return Objects.hash(encryptionInformation, payload, assertions); + } + + private static class PolicyBindingSerializer implements JsonDeserializer, JsonSerializer { + @Override + public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (json.isJsonObject()) { + return context.deserialize(json, Manifest.PolicyBinding.class); + } else if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { + return json.getAsString(); + } else { + throw new JsonParseException("Unexpected type for policyBinding"); + } + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context) { + return context.serialize(src, typeOfSrc); + } + } static public class Segment { public String hash; public long segmentSize; public long encryptedSegmentSize; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Segment segment = (Segment) o; + return segmentSize == segment.segmentSize && encryptedSegmentSize == segment.encryptedSegmentSize && Objects.equals(hash, segment.hash); + } + + @Override + public int hashCode() { + return Objects.hash(hash, segmentSize, encryptedSegmentSize); + } } static public class RootSignature { @@ -17,6 +68,19 @@ static public class RootSignature { public String algorithm; @SerializedName(value = "sig") public String signature; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RootSignature that = (RootSignature) o; + return Objects.equals(algorithm, that.algorithm) && Objects.equals(signature, that.signature); + } + + @Override + public int hashCode() { + return Objects.hash(algorithm, signature); + } } static public class IntegrityInformation { @@ -25,11 +89,37 @@ static public class IntegrityInformation { public int segmentSizeDefault; public int encryptedSegmentSizeDefault; public List segments; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IntegrityInformation that = (IntegrityInformation) o; + return segmentSizeDefault == that.segmentSizeDefault && encryptedSegmentSizeDefault == that.encryptedSegmentSizeDefault && Objects.equals(rootSignature, that.rootSignature) && Objects.equals(segmentHashAlg, that.segmentHashAlg) && Objects.equals(segments, that.segments); + } + + @Override + public int hashCode() { + return Objects.hash(rootSignature, segmentHashAlg, segmentSizeDefault, encryptedSegmentSizeDefault, segments); + } } static public class PolicyBinding { public String alg; public String hash; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PolicyBinding that = (PolicyBinding) o; + return Objects.equals(alg, that.alg) && Objects.equals(hash, that.hash); + } + + @Override + public int hashCode() { + return Objects.hash(alg, hash); + } } static public class KeyAccess { @@ -38,17 +128,43 @@ static public class KeyAccess { public String url; public String protocol; public String wrappedKey; - @JsonAdapter(TDF.PolicyBindingDeserializer.class) + @JsonAdapter(PolicyBindingSerializer.class) public Object policyBinding; public String encryptedMetadata; public String kid; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KeyAccess keyAccess = (KeyAccess) o; + return Objects.equals(keyType, keyAccess.keyType) && Objects.equals(url, keyAccess.url) && Objects.equals(protocol, keyAccess.protocol) && Objects.equals(wrappedKey, keyAccess.wrappedKey) && Objects.equals(policyBinding, keyAccess.policyBinding) && Objects.equals(encryptedMetadata, keyAccess.encryptedMetadata) && Objects.equals(kid, keyAccess.kid); + } + + @Override + public int hashCode() { + return Objects.hash(keyType, url, protocol, wrappedKey, policyBinding, encryptedMetadata, kid); + } } static public class Method { public String algorithm; public String iv; public Boolean IsStreamable; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Method method = (Method) o; + return Objects.equals(algorithm, method.algorithm) && Objects.equals(iv, method.iv) && Objects.equals(IsStreamable, method.IsStreamable); + } + + @Override + public int hashCode() { + return Objects.hash(algorithm, iv, IsStreamable); + } } @@ -62,6 +178,19 @@ static public class EncryptionInformation { public List keyAccessObj; public Method method; public IntegrityInformation integrityInformation; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EncryptionInformation that = (EncryptionInformation) o; + return Objects.equals(keyAccessType, that.keyAccessType) && Objects.equals(policy, that.policy) && Objects.equals(keyAccessObj, that.keyAccessObj) && Objects.equals(method, that.method) && Objects.equals(integrityInformation, that.integrityInformation); + } + + @Override + public int hashCode() { + return Objects.hash(keyAccessType, policy, keyAccessObj, method, integrityInformation); + } } static public class Payload { @@ -70,6 +199,19 @@ static public class Payload { public String protocol; public String mimeType; public Boolean isEncrypted; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Payload payload = (Payload) o; + return Objects.equals(type, payload.type) && Objects.equals(url, payload.url) && Objects.equals(protocol, payload.protocol) && Objects.equals(mimeType, payload.mimeType) && Objects.equals(isEncrypted, payload.isEncrypted); + } + + @Override + public int hashCode() { + return Objects.hash(type, url, protocol, mimeType, isEncrypted); + } } public EncryptionInformation encryptionInformation; diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index e1a456be..14661d0c 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -2,11 +2,12 @@ import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import com.nimbusds.jose.*; import com.nimbusds.jose.crypto.MACVerifier; import com.nimbusds.jose.crypto.RSASSAVerifier; @@ -14,18 +15,12 @@ import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.crypto.MACSigner; -import com.nimbusds.jose.jwk.RSAKey; -import io.opentdf.platform.kas.RewrapRequest; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; -import org.bouncycastle.pqc.crypto.lms.HSSSigner; import org.erdtman.jcs.JsonCanonicalizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -35,8 +30,6 @@ import java.nio.charset.StandardCharsets; import java.security.*; import java.text.ParseException; -import java.time.Duration; -import java.time.Instant; import java.util.*; public class TDF { @@ -74,19 +67,6 @@ public TDF() { private static final SecureRandom sRandom = new SecureRandom(); - public static class PolicyBindingDeserializer implements JsonDeserializer { - @Override - public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - if (json.isJsonObject()) { - return context.deserialize(json, Manifest.PolicyBinding.class); - } else if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { - return json.getAsString(); - } else { - throw new JsonParseException("Unexpected type for policyBinding"); - } - } - } - private static final Gson gson = new Gson(); public static class DataSizeNotSupported extends RuntimeException { diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 39d7e48c..33dd2275 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -4,7 +4,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -58,7 +61,8 @@ void testManifestMarshalAndUnMarshal() { " }\n" + "}"; - Manifest manifest = new Gson().fromJson(kManifestJsonFromTDF, Manifest.class); + Gson gson = new Gson(); + Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); // Test payload assertEquals(manifest.payload.url, "0.payload"); @@ -80,14 +84,9 @@ void testManifestMarshalAndUnMarshal() { assertEquals(manifest.encryptionInformation.integrityInformation.segmentHashAlg, "GMAC"); assertEquals(manifest.encryptionInformation.integrityInformation.segments.get(0).segmentSize, 1048576); - Manifest.Payload payload = new Manifest.Payload(); - payload.protocol = "zip"; + var serialized = gson.toJson(manifest); + var deserializedAgain = gson.fromJson(serialized, Manifest.class); - Manifest.EncryptionInformation encryptionInformation = manifest.encryptionInformation; - encryptionInformation.policy = "updated policy"; - - Manifest newManifest = new Manifest(); - newManifest.payload = payload; - newManifest.encryptionInformation = encryptionInformation; + assertEquals(manifest, deserializedAgain, "something changed when we deserialized -> serialized -> deserialized"); } } From f0c349d0311d7d4948c98c8a2a5a99795ee0dd55 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 24 Jul 2024 10:49:53 +0200 Subject: [PATCH 12/16] formatting --- .../java/io/opentdf/platform/sdk/ManifestTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 33dd2275..41b8780e 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -13,8 +13,8 @@ public class ManifestTest { @Test - void testManifestMarshalAndUnMarshal() { -String kManifestJsonFromTDF = "{\n" + + void testManifestMarshalAndUnMarshal() { + String kManifestJsonFromTDF = "{\n" + " \"encryptionInformation\": {\n" + " \"integrityInformation\": {\n" + " \"encryptedSegmentSizeDefault\": 1048604,\n" + @@ -61,8 +61,8 @@ void testManifestMarshalAndUnMarshal() { " }\n" + "}"; - Gson gson = new Gson(); - Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); + Gson gson = new Gson(); + Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); // Test payload assertEquals(manifest.payload.url, "0.payload"); @@ -76,7 +76,7 @@ void testManifestMarshalAndUnMarshal() { assertEquals(keyAccess.get(0).keyType, "wrapped"); assertEquals(keyAccess.get(0).protocol, "kas"); assertEquals(Manifest.PolicyBinding.class, keyAccess.get(0).policyBinding.getClass()); - var policyBinding = (Manifest.PolicyBinding)keyAccess.get(0).policyBinding; + var policyBinding = (Manifest.PolicyBinding) keyAccess.get(0).policyBinding; assertEquals(policyBinding.alg, "HS256"); assertEquals(policyBinding.hash, "YTgzNThhNzc5NWRhMjdjYThlYjk4ZmNmODliNzc2Y2E5ZmZiZDExZDQ3OTM5ODFjZTRjNmE3MmVjOTUzZTFlMA=="); assertEquals(manifest.encryptionInformation.method.algorithm, "AES-256-GCM"); From adf302c8d978b8eed96dc7764b2204736341aa3d Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 24 Jul 2024 14:02:36 +0200 Subject: [PATCH 13/16] Update ManifestTest.java --- sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index 41b8780e..b0ab5aa3 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -61,7 +61,9 @@ void testManifestMarshalAndUnMarshal() { " }\n" + "}"; - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + Gson gson = gsonBuilder.setPrettyPrinting().create(); + Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); // Test payload From 6f15009550143339c279b9f7d36ac0fc89c458f0 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 24 Jul 2024 14:02:51 +0200 Subject: [PATCH 14/16] Update ManifestTest.java --- sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java index b0ab5aa3..cc169d2f 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java @@ -63,7 +63,6 @@ void testManifestMarshalAndUnMarshal() { GsonBuilder gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.setPrettyPrinting().create(); - Manifest manifest = gson.fromJson(kManifestJsonFromTDF, Manifest.class); // Test payload From 4dc0241029b4cfc9cf41b55d2941b4aa3e9935e1 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy <35498075+elizabethhealy@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:08:28 -0400 Subject: [PATCH 15/16] fix: Prepend IV to ciphertext in encrypted metadata to match other sdks (#102) --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 14661d0c..c42db084 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -208,7 +208,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { EncryptedMetadata encryptedMetadata = new EncryptedMetadata(); encryptedMetadata.iv = encoder.encodeToString(encrypted.getIv()); - encryptedMetadata.ciphertext = encoder.encodeToString(encrypted.getCiphertext()); + encryptedMetadata.ciphertext = encoder.encodeToString(encrypted.asBytes()); var metadata = gson.toJson(encryptedMetadata); keyAccess.encryptedMetadata = encoder.encodeToString(metadata.getBytes(StandardCharsets.UTF_8)); @@ -516,7 +516,6 @@ public Reader loadTDF(SeekableByteChannel tdf, Config.AssertionConfig assertionC EncryptedMetadata encryptedMetadata = gson.fromJson(decodedMetadata, EncryptedMetadata.class); var encryptedData = new AesGcm.Encrypted( - decoder.decode(encryptedMetadata.iv), decoder.decode(encryptedMetadata.ciphertext) ); From 11568f81a56d4e463686099e5a3832b452ec4726 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy <35498075+elizabethhealy@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:22:51 -0400 Subject: [PATCH 16/16] remove double ; Co-authored-by: Paul Flynn <43211074+pflynn-virtru@users.noreply.github.com> --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index c42db084..ae33577c 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -192,7 +192,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { var hexBinding = Hex.encodeHexString(CryptoUtils.CalculateSHA256Hmac(symKey, base64PolicyObject.getBytes(StandardCharsets.UTF_8))); var policyBinding = new Manifest.PolicyBinding(); policyBinding.alg = kHmacIntegrityAlgorithm; - policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8));; + policyBinding.hash = encoder.encodeToString(hexBinding.getBytes(StandardCharsets.UTF_8)); keyAccess.policyBinding = policyBinding; // Wrap the key with kas public key