From 7fb5eba504969080eda159748fc66b0a61b68c09 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 25 Jul 2025 14:21:32 +0200 Subject: [PATCH 1/9] feat(sdk): add base key support for nanotdf --- .../io/opentdf/platform/sdk/ECKeyPair.java | 1 - .../java/io/opentdf/platform/sdk/NanoTDF.java | 52 +++++++++---- .../io/opentdf/platform/sdk/NanoTDFTest.java | 75 +++++++++++++++---- 3 files changed, 100 insertions(+), 28 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java index 93b09557..c2c82ffe 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java @@ -215,7 +215,6 @@ public static ECPrivateKey privateKeyFromPem(String pemEncoding) { parser.close(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER); - ; return (ECPrivateKey) converter.getPrivateKey(privateKeyInfo); } catch (IOException e) { throw new RuntimeException(e); diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index 2ea97801..a6b18f4f 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -16,6 +16,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import io.opentdf.platform.wellknownconfiguration.WellKnownServiceClientInterface; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,32 @@ public InvalidNanoTDFConfig(String errorMessage) { } } + private static Optional getBaseKey(WellKnownServiceClientInterface wellKnownService) { + var key = Planner.fetchBaseKey(wellKnownService); + key.ifPresent(k -> { + if (!KeyType.fromAlgorithm(k.getPublicKey().getAlgorithm()).isEc()) { + throw new SDKException(String.format("base key is not an EC key, cannot create NanoTDF using a key of type %s", + k.getPublicKey().getAlgorithm())); + } + }); + + return key.map(Config.KASInfo::fromSimpleKasKey); + } + + private Optional getKasInfo(Config.NanoTDFConfig nanoTDFConfig) { + if (nanoTDFConfig.kasInfoList.isEmpty()) { + logger.debug("no kas info provided in NanoTDFConfig"); + return Optional.empty(); + } + Config.KASInfo kasInfo = nanoTDFConfig.kasInfoList.get(0); + String url = kasInfo.URL; + if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) { + logger.info("no public key provided for KAS at {}, retrieving", url); + kasInfo = services.kas().getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getCurve()); + } + return Optional.of(kasInfo); + } + private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) throws InvalidNanoTDFConfig, UnsupportedNanoTDFFeature { if (nanoTDFConfig.collectionConfig.useCollection) { Config.HeaderInfo headerInfo = nanoTDFConfig.collectionConfig.getHeaderInfo(); @@ -74,11 +101,12 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro } Gson gson = new GsonBuilder().create(); - if (nanoTDFConfig.kasInfoList.isEmpty()) { - throw new InvalidNanoTDFConfig("kas url is missing"); + Optional maybeKas = getKasInfo(nanoTDFConfig).or(() -> NanoTDF.getBaseKey(services.wellknown())); + if (maybeKas.isEmpty()) { + throw new SDKException("no KAS info provided and couldn't get base key, cannot create NanoTDF"); } - Config.KASInfo kasInfo = nanoTDFConfig.kasInfoList.get(0); + Config.KASInfo kasInfo = maybeKas.get(); String url = kasInfo.URL; if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) { logger.info("no public key provided for KAS at {}, retrieving", url); @@ -86,7 +114,7 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro } // Kas url resource locator - ResourceLocator kasURL = new ResourceLocator(nanoTDFConfig.kasInfoList.get(0).URL, kasInfo.KID); + ResourceLocator kasURL = new ResourceLocator(kasInfo.URL, kasInfo.KID); assert kasURL.getIdentifier() != null : "Identifier in ResourceLocator cannot be null"; NanoTDFType.ECCurve ecCurve = getEcCurve(nanoTDFConfig, kasInfo); @@ -139,12 +167,10 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro // Create header byte[] compressedPubKey = keyPair.compressECPublickey(); Header header = new Header(); - ECCMode mode; - if (nanoTDFConfig.eccMode.getCurve() != keyPair.getCurve()) { - mode = new ECCMode(nanoTDFConfig.eccMode.getECCModeAsByte()); - mode.setEllipticCurve(keyPair.getCurve()); - } else { - mode = nanoTDFConfig.eccMode; + ECCMode mode = new ECCMode(); + mode.setEllipticCurve(keyPair.getCurve()); + if (logger.isWarnEnabled() && !nanoTDFConfig.eccMode.equals(mode)) { + logger.warn("ECC mode provided in NanoTDFConfig: {}, ECC mode from key: {}", nanoTDFConfig.eccMode.getCurve(), mode.getCurve()); } header.setECCMode(mode); header.setPayloadConfig(nanoTDFConfig.config); @@ -169,10 +195,10 @@ private static NanoTDFType.ECCurve getEcCurve(Config.NanoTDFConfig nanoTDFConfig logger.info("no curve specified in KASInfo, using the curve from config [{}]", nanoTDFConfig.eccMode.getCurve()); ecCurve = nanoTDFConfig.eccMode.getCurve(); } else { - if (specifiedCurve.get() != nanoTDFConfig.eccMode.getCurve()) { - logger.warn("ECCurve in NanoTDFConfig [{}] does not match the curve in KASInfo, using KASInfo curve [{}]", nanoTDFConfig.eccMode.getCurve(), specifiedCurve); - } ecCurve = specifiedCurve.get(); + if (ecCurve != nanoTDFConfig.eccMode.getCurve()) { + logger.warn("ECCurve in NanoTDFConfig [{}] does not match the curve in KASInfo, using KASInfo curve [{}]", nanoTDFConfig.eccMode.getCurve(), ecCurve); + } } return ecCurve; } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index 73c38087..2b113ff8 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -2,6 +2,8 @@ import com.connectrpc.ResponseMessage; import com.connectrpc.UnaryBlockingCall; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; import io.opentdf.platform.policy.KeyAccessServer; import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceClient; import io.opentdf.platform.policy.kasregistry.ListKeyAccessServersRequest; @@ -11,6 +13,8 @@ import java.nio.charset.StandardCharsets; +import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationResponse; +import io.opentdf.platform.wellknownconfiguration.WellKnownServiceClientInterface; import org.apache.commons.io.output.ByteArrayOutputStream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -23,6 +27,7 @@ import java.util.Base64; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Random; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -45,14 +50,27 @@ public class NanoTDFTest { "oVP7Vpcx\n" + "-----END PRIVATE KEY-----"; + private static final String BASE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" + + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/NawR/F7RJfX/odyOLPjl+5Ce1Br\n" + + "QZ/MBCIerHe26HzlBSbpa7HQHZx9PYVamHTw9+iJCY3dm8Uwp4Ab2uehnA==\n" + + "-----END PUBLIC KEY-----"; + + private static final String BASE_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" + + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgB3YtAvS7lctHlPsq\n" + + "bZI8OX1B9W1c4GAIxzwKzD6iPkqhRANCAAT81rBH8XtEl9f+h3I4s+OX7kJ7UGtB\n" + + "n8wEIh6sd7bofOUFJulrsdAdnH09hVqYdPD36IkJjd2bxTCngBva56Gc\n" + + "-----END PRIVATE KEY-----" ; + private static final String KID = "r1"; + private static final String BASE_KID = "basekid"; protected static KeyAccessServerRegistryServiceClient kasRegistryService; protected static List registeredKases = List.of( "https://api.example.com/kas", "https://other.org/kas2", "http://localhost:8181/kas", - "https://localhost:8383/kas" + "https://localhost:8383/kas", + "https://api.kaswithbasekey.example.com" ); protected static String platformUrl = "http://localhost:8080"; @@ -70,10 +88,16 @@ public Config.KASInfo getPublicKey(Config.KASInfo kasInfo) { @Override public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) { + var k2 = kasInfo.clone(); + if (Objects.equals(kasInfo.KID, BASE_KID)) { + assertThat(kasInfo.URL).isEqualTo("https://api.kaswithbasekey.example.com"); + assertThat(kasInfo.Algorithm).isEqualTo("ec:secp384r1"); + k2.PublicKey = BASE_PUBLIC_KEY; + return k2; + } if (kasInfo.Algorithm != null && !"ec:secp256r1".equals(kasInfo.Algorithm)) { throw new IllegalArgumentException("Unexpected algorithm: " + kasInfo); } - var k2 = kasInfo.clone(); k2.KID = KID; k2.PublicKey = kasPublicKey; k2.Algorithm = "ec:secp256r1"; @@ -82,19 +106,14 @@ public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) @Override public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy, KeyType sessionKeyType) { - int index = Integer.parseInt(keyAccess.url); - var decryptor = new AsymDecryption(keypairs.get(index).getPrivate()); - var bytes = Base64.getDecoder().decode(keyAccess.wrappedKey); - try { - return decryptor.decrypt(bytes); - } catch (Exception e) { - throw new RuntimeException(e); - } + throw new UnsupportedOperationException("no unwrapping ZTDFs here"); } @Override public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL) { - + String key = Objects.equals(kasURL, "https://api.kaswithbasekey.example.com") + ? BASE_PRIVATE_KEY + : kasPrivateKey; byte[] headerAsBytes = Base64.getDecoder().decode(header); Header nTDFHeader = new Header(ByteBuffer.wrap(headerAsBytes)); byte[] ephemeralKey = nTDFHeader.getEphemeralKey(); @@ -103,7 +122,7 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas // Generate symmetric key byte[] symmetricKey = ECKeyPair.computeECDHKey(ECKeyPair.publicKeyFromPem(publicKeyAsPem), - ECKeyPair.privateKeyFromPem(kasPrivateKey)); + ECKeyPair.privateKeyFromPem(key)); // Generate HKDF key MessageDigest digest; @@ -113,8 +132,7 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas throw new SDKException("error creating SHA-256 message digest", e); } byte[] hashOfSalt = digest.digest(NanoTDF.MAGIC_NUMBER_AND_VERSION); - byte[] key = ECKeyPair.calculateHKDF(hashOfSalt, symmetricKey); - return key; + return ECKeyPair.calculateHKDF(hashOfSalt, symmetricKey); } @Override @@ -203,6 +221,35 @@ void encryptionAndDecryptionWithValidKey() throws Exception { } } + @Test + void encryptionAndDecryptWithBaseKey() throws Exception { + var baseKeyJson = "{\"kas_url\":\"https://api.kaswithbasekey.example.com\",\"public_key\":{\"algorithm\":\"ALGORITHM_EC_P256\",\"kid\":\"" + BASE_KID + "\",\"pem\": \"" + BASE_PUBLIC_KEY + "\"}}"; + var val = Value.newBuilder().setStringValue(baseKeyJson).build(); + var config = Struct.newBuilder().putFields("base_key", val).build(); + WellKnownServiceClientInterface wellknown = mock(WellKnownServiceClientInterface.class); + GetWellKnownConfigurationResponse response = GetWellKnownConfigurationResponse.newBuilder().setConfiguration(config).build(); + when(wellknown.getWellKnownConfigurationBlocking(any(), any())).thenReturn(TestUtil.successfulUnaryCall(response)); + Config.NanoTDFConfig nanoConfig = Config.newNanoTDFConfig( + Config.witDataAttributes("https://example.com/attr/Classification/value/S", + "https://example.com/attr/Classification/value/X") + ); + + String plainText = "Virtru!!"; + ByteBuffer byteBuffer = ByteBuffer.wrap(plainText.getBytes()); + ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); + NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).setWellknownService(wellknown).build()); + nanoTDF.createNanoTDF(byteBuffer, tdfOutputStream, nanoConfig); + + byte[] nanoTDFBytes = tdfOutputStream.toByteArray(); + ByteArrayOutputStream plainTextStream = new ByteArrayOutputStream(); + nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, platformUrl); + String out = new String(plainTextStream.toByteArray(), StandardCharsets.UTF_8); + assertThat(out).isEqualTo(plainText); + // KAS KID + assertThat(new String(nanoTDFBytes, StandardCharsets.UTF_8)).contains(BASE_KID); + } + @Test void testWithDifferentConfigAndKeyValues() throws Exception { var kasInfos = new ArrayList<>(); From ba0acbe5a47514c2a1eb3583236473fc6f7d59f1 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 25 Jul 2025 17:20:41 +0200 Subject: [PATCH 2/9] Update sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index 2b113ff8..ef1388ec 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -59,7 +59,7 @@ public class NanoTDFTest { "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgB3YtAvS7lctHlPsq\n" + "bZI8OX1B9W1c4GAIxzwKzD6iPkqhRANCAAT81rBH8XtEl9f+h3I4s+OX7kJ7UGtB\n" + "n8wEIh6sd7bofOUFJulrsdAdnH09hVqYdPD36IkJjd2bxTCngBva56Gc\n" + - "-----END PRIVATE KEY-----" ; + "-----END PRIVATE KEY-----"; private static final String KID = "r1"; private static final String BASE_KID = "basekid"; From c5adbd8975538e7cb30f52c1e1600c9e423959f4 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 08:48:12 +0200 Subject: [PATCH 3/9] don't throw away old config values --- .../java/io/opentdf/platform/sdk/NanoTDF.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index a6b18f4f..2ae53c9e 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -83,13 +83,7 @@ private Optional getKasInfo(Config.NanoTDFConfig nanoTDFConfig) logger.debug("no kas info provided in NanoTDFConfig"); return Optional.empty(); } - Config.KASInfo kasInfo = nanoTDFConfig.kasInfoList.get(0); - String url = kasInfo.URL; - if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) { - logger.info("no public key provided for KAS at {}, retrieving", url); - kasInfo = services.kas().getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getCurve()); - } - return Optional.of(kasInfo); + return Optional.of(nanoTDFConfig.kasInfoList.get(0)); } private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) throws InvalidNanoTDFConfig, UnsupportedNanoTDFFeature { @@ -167,10 +161,17 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro // Create header byte[] compressedPubKey = keyPair.compressECPublickey(); Header header = new Header(); - ECCMode mode = new ECCMode(); - mode.setEllipticCurve(keyPair.getCurve()); - if (logger.isWarnEnabled() && !nanoTDFConfig.eccMode.equals(mode)) { - logger.warn("ECC mode provided in NanoTDFConfig: {}, ECC mode from key: {}", nanoTDFConfig.eccMode.getCurve(), mode.getCurve()); + ECCMode mode; + if (nanoTDFConfig.eccMode.getCurve() != keyPair.getCurve()) { + if (logger.isWarnEnabled()) { + logger.warn("ECC mode provided in NanoTDFConfig differs from mode in key. config = [{}], key = [{}]", + nanoTDFConfig.eccMode.getCurve(), + keyPair.getCurve()); + } + mode = new ECCMode(nanoTDFConfig.eccMode.getECCModeAsByte()); + mode.setEllipticCurve(keyPair.getCurve()); + } else { + mode = nanoTDFConfig.eccMode; } header.setECCMode(mode); header.setPayloadConfig(nanoTDFConfig.config); From dfd925f62ab0927c84afca1846adb2eb0129c94a Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 09:01:14 +0200 Subject: [PATCH 4/9] this is redundant --- sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index 2ae53c9e..a061fb88 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -163,11 +163,6 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro Header header = new Header(); ECCMode mode; if (nanoTDFConfig.eccMode.getCurve() != keyPair.getCurve()) { - if (logger.isWarnEnabled()) { - logger.warn("ECC mode provided in NanoTDFConfig differs from mode in key. config = [{}], key = [{}]", - nanoTDFConfig.eccMode.getCurve(), - keyPair.getCurve()); - } mode = new ECCMode(nanoTDFConfig.eccMode.getECCModeAsByte()); mode.setEllipticCurve(keyPair.getCurve()); } else { From 16b8f76fc1f739d8ca440579a916f0047c2cbe6b Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 09:25:45 +0200 Subject: [PATCH 5/9] Update NanoTDFTest.java --- sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index ef1388ec..0979852a 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -88,13 +88,6 @@ public Config.KASInfo getPublicKey(Config.KASInfo kasInfo) { @Override public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) { - var k2 = kasInfo.clone(); - if (Objects.equals(kasInfo.KID, BASE_KID)) { - assertThat(kasInfo.URL).isEqualTo("https://api.kaswithbasekey.example.com"); - assertThat(kasInfo.Algorithm).isEqualTo("ec:secp384r1"); - k2.PublicKey = BASE_PUBLIC_KEY; - return k2; - } if (kasInfo.Algorithm != null && !"ec:secp256r1".equals(kasInfo.Algorithm)) { throw new IllegalArgumentException("Unexpected algorithm: " + kasInfo); } From de956834dabe664ab6f217ecb334fb7c05fb245a Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 09:26:56 +0200 Subject: [PATCH 6/9] Update NanoTDFTest.java --- sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index 0979852a..cffccdf0 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -91,6 +91,7 @@ public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) if (kasInfo.Algorithm != null && !"ec:secp256r1".equals(kasInfo.Algorithm)) { throw new IllegalArgumentException("Unexpected algorithm: " + kasInfo); } + var k2 = kasInfo.clone(); k2.KID = KID; k2.PublicKey = kasPublicKey; k2.Algorithm = "ec:secp256r1"; From a6db5ca775015ecad142e03335eb31a66902ecec Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 09:28:17 +0200 Subject: [PATCH 7/9] cleanup --- sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index ef1388ec..1d9593d5 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -76,7 +76,7 @@ public class NanoTDFTest { protected static SDK.KAS kas = new SDK.KAS() { @Override - public void close() throws Exception { + public void close() { } @Override @@ -91,7 +91,7 @@ public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) var k2 = kasInfo.clone(); if (Objects.equals(kasInfo.KID, BASE_KID)) { assertThat(kasInfo.URL).isEqualTo("https://api.kaswithbasekey.example.com"); - assertThat(kasInfo.Algorithm).isEqualTo("ec:secp384r1"); + assertThat(kasInfo.Algorithm).isEqualTo("ec:secp256r1"); k2.PublicKey = BASE_PUBLIC_KEY; return k2; } From 06e1375b735b99a84f57bca0699c194a1652ed75 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 10:01:55 +0200 Subject: [PATCH 8/9] Update sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../java/io/opentdf/platform/sdk/NanoTDF.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index a061fb88..4c056b60 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -67,15 +67,13 @@ public InvalidNanoTDFConfig(String errorMessage) { } private static Optional getBaseKey(WellKnownServiceClientInterface wellKnownService) { - var key = Planner.fetchBaseKey(wellKnownService); - key.ifPresent(k -> { - if (!KeyType.fromAlgorithm(k.getPublicKey().getAlgorithm()).isEc()) { - throw new SDKException(String.format("base key is not an EC key, cannot create NanoTDF using a key of type %s", - k.getPublicKey().getAlgorithm())); - } - }); - - return key.map(Config.KASInfo::fromSimpleKasKey); +return Planner.fetchBaseKey(wellKnownService).map(k -> { + if (!KeyType.fromAlgorithm(k.getPublicKey().getAlgorithm()).isEc()) { + throw new SDKException(String.format("base key is not an EC key, cannot create NanoTDF using a key of type %s", + k.getPublicKey().getAlgorithm())); + } + return Config.KASInfo.fromSimpleKasKey(k); +}); } private Optional getKasInfo(Config.NanoTDFConfig nanoTDFConfig) { From 2f876e8d38c5a009b567606dd44e670ceb2785f7 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 28 Jul 2025 10:03:14 +0200 Subject: [PATCH 9/9] gemini --- sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index a061fb88..67389221 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -95,12 +95,10 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro } Gson gson = new GsonBuilder().create(); - Optional maybeKas = getKasInfo(nanoTDFConfig).or(() -> NanoTDF.getBaseKey(services.wellknown())); - if (maybeKas.isEmpty()) { - throw new SDKException("no KAS info provided and couldn't get base key, cannot create NanoTDF"); - } + Config.KASInfo kasInfo = getKasInfo(nanoTDFConfig) + .or(() -> NanoTDF.getBaseKey(services.wellknown())) + .orElseThrow(() -> new SDKException("no KAS info provided and couldn't get base key, cannot create NanoTDF")); - Config.KASInfo kasInfo = maybeKas.get(); String url = kasInfo.URL; if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) { logger.info("no public key provided for KAS at {}, retrieving", url);