diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml
index 9961d031..c2785110 100644
--- a/.github/workflows/checks.yaml
+++ b/.github/workflows/checks.yaml
@@ -138,21 +138,21 @@ jobs:
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             encrypt --kas-url=localhost:8080 --mime-type=text/plain --attr https://example.com/attr/attr1/value/value1 --autoconfigure=false -f data -m 'here is some metadata' > test.tdf
 
           java -jar target/cmdline.jar \
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             decrypt -f test.tdf > decrypted
 
           java -jar target/cmdline.jar \
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             metadata -f test.tdf > metadata
 
           if ! diff -q data decrypted; then
@@ -174,14 +174,14 @@ jobs:
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             encryptnano --kas-url=http://localhost:8080 --attr https://example.com/attr/attr1/value/value1 -f data -m 'here is some metadata' > nano.ntdf
 
           java -jar target/cmdline.jar \
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             decryptnano -f nano.ntdf > decrypted
           
           if ! diff -q data decrypted; then
@@ -216,21 +216,21 @@ jobs:
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             encrypt --kas-url=localhost:8080,localhost:8282 -f data -m 'here is some metadata' > test.tdf
 
           java -jar target/cmdline.jar \
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             decrypt -f test.tdf > decrypted
 
           java -jar target/cmdline.jar \
             --client-id=opentdf-sdk \
             --client-secret=secret \
             --platform-endpoint=localhost:8080 \
-            -i -h \
+            -h\
             metadata -f test.tdf > metadata
 
           if ! diff -q data decrypted; then
diff --git a/.gitignore b/.gitignore
index 476c7749..35853a81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
-protocol/src/main/protogen
+sdk/src/main/protogen
 /.idea/
 target/
 .vscode/
 .DS_Store
+sdk/sample.tdf
\ No newline at end of file
diff --git a/buf.gen.yaml b/buf.gen.yaml
index e829ee09..797abc12 100644
--- a/buf.gen.yaml
+++ b/buf.gen.yaml
@@ -9,6 +9,6 @@ managed:
       - buf.build/grpc-ecosystem/grpc-gateway
 plugins:
   - plugin: buf.build/protocolbuffers/java:v25.3
-    out: protocol/src/main/protogen
+    out: sdk/src/main/protogen
   - plugin: buf.build/grpc/java:v1.61.1
-    out: protocol/src/main/protogen
+    out: sdk/src/main/protogen
diff --git a/cmdline/pom.xml b/cmdline/pom.xml
index 65b0d13e..8d7a128f 100644
--- a/cmdline/pom.xml
+++ b/cmdline/pom.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>io.opentdf.platform</groupId>
         <artifactId>sdk-pom</artifactId>
-        <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
+        <version>${revision}</version>
     </parent>
     <artifactId>cmdline</artifactId>
     <properties>
@@ -18,27 +18,52 @@
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <version>3.7.1</version>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.5.3</version>
                 <executions>
                     <execution>
                         <phase>package</phase>
                         <goals>
-                            <goal>single</goal>
+                            <goal>shade</goal>
                         </goals>
+                        <configuration>
+
+                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                            <finalName>cmdline</finalName>
+                            <transformers>
+                                <transformer
+                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>io.opentdf.platform.TDF</mainClass>
+                                    <manifestEntries>
+                                        <Implementation-Version>${version}</Implementation-Version>
+                                        <Main-Class>io.opentdf.platform.TDF</Main-Class>
+                                    </manifestEntries>
+                                </transformer>
+                                <transformer
+                                    implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+                            </transformers>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/*.SF</exclude>
+                                        <exclude>META-INF/*.DSA</exclude>
+                                        <exclude>META-INF/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                        </configuration>
                     </execution>
                 </executions>
+            </plugin>
+
+            <!-- Skip deployment for this child module -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>3.1.1</version>
                 <configuration>
-                    <descriptorRefs>
-                        <descriptorRef>jar-with-dependencies</descriptorRef>
-                    </descriptorRefs>
-                    <finalName>cmdline</finalName>
-                    <appendAssemblyId>false</appendAssemblyId>
-                    <archive>
-                        <manifest>
-                            <mainClass>io.opentdf.platform.TDF</mainClass>
-                        </manifest>
-                    </archive>
+                    <skip>true</skip>
                 </configuration>
             </plugin>
         </plugins>
@@ -52,7 +77,7 @@
         <dependency>
             <groupId>io.opentdf.platform</groupId>
             <artifactId>sdk</artifactId>
-            <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
+            <version>${project.version}</version>
         </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java
index ca784283..71770cd2 100644
--- a/cmdline/src/main/java/io/opentdf/platform/Command.java
+++ b/cmdline/src/main/java/io/opentdf/platform/Command.java
@@ -39,31 +39,32 @@
 @CommandLine.Command(name = "tdf")
 class Command {
 
-    @Option(names = {"--client-secret"}, required = true)
+    @Option(names = { "--client-secret" }, required = true)
     private String clientSecret;
 
-    @Option(names = {"-h", "--plaintext"}, defaultValue = "false")
+    @Option(names = { "-h", "--plaintext" }, defaultValue = "false")
     private boolean plaintext;
 
-    @Option(names = {"-i", "--insecure"}, defaultValue = "false")
+    @Option(names = { "-i", "--insecure" }, defaultValue = "false")
     private boolean insecure;
 
-    @Option(names = {"--client-id"}, required = true)
+    @Option(names = { "--client-id" }, required = true)
     private String clientId;
 
-    @Option(names = {"-p", "--platform-endpoint"}, required = true)
+    @Option(names = { "-p", "--platform-endpoint" }, required = true)
     private String platformEndpoint;
 
     @CommandLine.Command(name = "encrypt")
     void encrypt(
-            @Option(names = {"-f", "--file"}, defaultValue = Option.NULL_VALUE) Optional<File> file,
-            @Option(names = {"-k", "--kas-url"}, required = true, split = ",") List<String> kas,
-            @Option(names = {"-m", "--metadata"}, defaultValue = Option.NULL_VALUE) Optional<String> metadata,
+            @Option(names = { "-f", "--file" }, defaultValue = Option.NULL_VALUE) Optional<File> file,
+            @Option(names = { "-k", "--kas-url" }, required = true, split = ",") List<String> kas,
+            @Option(names = { "-m", "--metadata" }, defaultValue = Option.NULL_VALUE) Optional<String> metadata,
             // cant split on optional parameters
-            @Option(names = {"-a", "--attr"}, defaultValue = Option.NULL_VALUE) Optional<String> attributes,
-            @Option(names = {"-c", "--autoconfigure"}, defaultValue = Option.NULL_VALUE) Optional<Boolean> autoconfigure,
-            @Option(names = {"--mime-type"}, defaultValue = Option.NULL_VALUE) Optional<String> mimeType) throws
-            IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException {
+            @Option(names = { "-a", "--attr" }, defaultValue = Option.NULL_VALUE) Optional<String> attributes,
+            @Option(names = { "-c",
+                    "--autoconfigure" }, defaultValue = Option.NULL_VALUE) Optional<Boolean> autoconfigure,
+            @Option(names = { "--mime-type" }, defaultValue = Option.NULL_VALUE) Optional<String> mimeType)
+            throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException {
 
         var sdk = buildSDK();
         var kasInfos = kas.stream().map(k -> {
@@ -71,57 +72,55 @@ void encrypt(
             ki.URL = k;
             return ki;
         }).toArray(Config.KASInfo[]::new);
-        
 
         List<Consumer<Config.TDFConfig>> configs = new ArrayList<>();
         configs.add(Config.withKasInformation(kasInfos));
         metadata.map(Config::withMetaData).ifPresent(configs::add);
         autoconfigure.map(Config::withAutoconfigure).ifPresent(configs::add);
         mimeType.map(Config::withMimeType).ifPresent(configs::add);
-        if (attributes.isPresent()){
+        if (attributes.isPresent()) {
             configs.add(Config.withDataAttributes(attributes.get().split(",")));
         }
         var tdfConfig = Config.newTDFConfig(configs.toArray(Consumer[]::new));
         try (var in = file.isEmpty() ? new BufferedInputStream(System.in) : new FileInputStream(file.get())) {
             try (var out = new BufferedOutputStream(System.out)) {
-                new TDF().createTDF(in, out, tdfConfig, 
-                    sdk.getServices().kas(), 
-                    sdk.getServices().attributes()
-                );
+                new TDF().createTDF(in, out, tdfConfig,
+                        sdk.getServices().kas(),
+                        sdk.getServices().attributes());
             }
         }
     }
 
     private SDK buildSDK() {
         SDKBuilder builder = new SDKBuilder();
-        if (insecure){
+        if (insecure) {
             SSLFactory sslFactory = SSLFactory.builder()
-            .withUnsafeTrustMaterial() // Trust all certificates
-            .build();
+                    .withUnsafeTrustMaterial() // Trust all certificates
+                    .build();
             builder.sslFactory(sslFactory);
         }
-        
-        return  builder.platformEndpoint(platformEndpoint)
-                .clientSecret(clientId, clientSecret)
-                .useInsecurePlaintextConnection(plaintext)
+
+        return builder.platformEndpoint(platformEndpoint)
+                .clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(plaintext)
                 .build();
     }
 
     @CommandLine.Command(name = "decrypt")
-    void decrypt(@Option(names = {"-f", "--file"}, required = true) Path tdfPath) throws IOException,
+    void decrypt(@Option(names = { "-f", "--file" }, required = true) Path tdfPath) throws IOException,
             InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException,
             BadPaddingException, InvalidKeyException, TDF.FailedToCreateGMAC,
             JOSEException, ParseException, NoSuchAlgorithmException, DecoderException {
         var sdk = buildSDK();
         try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) {
             try (var stdout = new BufferedOutputStream(System.out)) {
-                    var reader = new TDF().loadTDF(in, sdk.getServices().kas());
-                    reader.readPayload(stdout);
-                }
+                var reader = new TDF().loadTDF(in, sdk.getServices().kas());
+                reader.readPayload(stdout);
+            }
         }
     }
+
     @CommandLine.Command(name = "metadata")
-    void readMetadata(@Option(names = {"-f", "--file"}, required = true) Path tdfPath) throws IOException,
+    void readMetadata(@Option(names = { "-f", "--file" }, required = true) Path tdfPath) throws IOException,
             TDF.FailedToCreateGMAC, JOSEException, NoSuchAlgorithmException, ParseException, DecoderException {
         var sdk = buildSDK();
 
@@ -135,10 +134,11 @@ void readMetadata(@Option(names = {"-f", "--file"}, required = true) Path tdfPat
 
     @CommandLine.Command(name = "encryptnano")
     void createNanoTDF(
-            @Option(names = {"-f", "--file"}, defaultValue = Option.NULL_VALUE) Optional<File> file,
-            @Option(names = {"-k", "--kas-url"}, required = true) List<String> kas,
-            @Option(names = {"-m", "--metadata"}, defaultValue = Option.NULL_VALUE) Optional<String> metadata,
-            @Option(names = {"-a", "--attr"}, defaultValue = Option.NULL_VALUE) Optional<String> attributes) throws Exception {
+            @Option(names = { "-f", "--file" }, defaultValue = Option.NULL_VALUE) Optional<File> file,
+            @Option(names = { "-k", "--kas-url" }, required = true) List<String> kas,
+            @Option(names = { "-m", "--metadata" }, defaultValue = Option.NULL_VALUE) Optional<String> metadata,
+            @Option(names = { "-a", "--attr" }, defaultValue = Option.NULL_VALUE) Optional<String> attributes)
+            throws Exception {
 
         var sdk = buildSDK();
         var kasInfos = kas.stream().map(k -> {
@@ -163,7 +163,7 @@ void createNanoTDF(
     }
 
     @CommandLine.Command(name = "decryptnano")
-    void readNanoTDF(@Option(names = {"-f", "--file"}, required = true) Path nanoTDFPath) throws Exception {
+    void readNanoTDF(@Option(names = { "-f", "--file" }, required = true) Path nanoTDFPath) throws Exception {
         var sdk = buildSDK();
         try (var in = FileChannel.open(nanoTDFPath, StandardOpenOption.READ)) {
             try (var stdout = new BufferedOutputStream(System.out)) {
diff --git a/pom.xml b/pom.xml
index 1b3475e0..317d9f21 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,26 +1,27 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>io.opentdf.platform</groupId>
     <artifactId>sdk-pom</artifactId>
-    <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
+    <version>${revision}</version>
     <name>sdk-pom</name>
     <packaging>pom</packaging>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-<!--        TODO: Move to new version of Java-->
+        <!--        TODO: Move to new version of Java-->
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
         <log4j.version>2.20.0</log4j.version>
         <grpc.version>1.63.0</grpc.version>
         <protobuf.version>3.25.3</protobuf.version>
         <sslcontext.version>8.3.5</sslcontext.version>
+        <revision>0.6.2-SNAPSHOT</revision>
     </properties>
     <modules>
-        <module>protocol</module>
         <module>sdk</module>
         <module>cmdline</module>
     </modules>
@@ -114,14 +115,17 @@
     </dependencyManagement>
 
     <build>
-        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
+        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be
+            moved to parent pom) -->
             <plugins>
-                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
+                <!-- clean lifecycle, see
+                https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                 <plugin>
                     <artifactId>maven-clean-plugin</artifactId>
                     <version>3.1.0</version>
                 </plugin>
-                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
+                <!-- default lifecycle, jar packaging: see
+                https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                 <plugin>
                     <artifactId>maven-resources-plugin</artifactId>
                     <version>3.0.2</version>
@@ -146,7 +150,8 @@
                     <artifactId>maven-deploy-plugin</artifactId>
                     <version>2.8.2</version>
                 </plugin>
-                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
+                <!-- site lifecycle, see
+                https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                 <plugin>
                     <artifactId>maven-site-plugin</artifactId>
                     <version>3.7.1</version>
@@ -162,10 +167,10 @@
                     <configuration>
                         <failFast>false</failFast>
                         <rules>
-                            <dependencyConvergence/>
-                            <requireUpperBoundDeps/>
-                            <requireSameVersions/>
-                            <banDuplicatePomDependencyVersions/>
+                            <dependencyConvergence />
+                            <requireUpperBoundDeps />
+                            <requireSameVersions />
+                            <banDuplicatePomDependencyVersions />
                         </rules>
                     </configuration>
                 </plugin>
@@ -187,12 +192,12 @@
                             <version>${maven.compiler.target}</version>
                             <level>WARN</level>
                         </requireJavaVersion>
-                        <dependencyConvergence/>
-                        <requireUpperBoundDeps/>
-                        <requireSameVersions/>
-                        <requirePluginVersions/>
-                        <banDuplicatePomDependencyVersions/>
-                        <reactorModuleConvergence/>
+                        <dependencyConvergence />
+                        <requireUpperBoundDeps />
+                        <requireSameVersions />
+                        <requirePluginVersions />
+                        <banDuplicatePomDependencyVersions />
+                        <reactorModuleConvergence />
                     </rules>
                 </configuration>
                 <executions>
@@ -234,5 +239,4 @@
         </profile>
 
     </profiles>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/protocol/pom.xml b/protocol/pom.xml
deleted file mode 100644
index 143caf39..00000000
--- a/protocol/pom.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>io.opentdf.platform</groupId>
-    <name>protocol</name>
-    <artifactId>protocol</artifactId>
-    <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
-    <parent>
-        <artifactId>sdk-pom</artifactId>
-        <groupId>io.opentdf.platform</groupId>
-        <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
-    </parent>
-    <packaging>jar</packaging>
-    <dependencies>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java</artifactId>
-            <version>${protobuf.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.annotation</groupId>
-            <artifactId>javax.annotation-api</artifactId>
-            <version>1.3.2</version>
-        </dependency>
-        <dependency>
-            <groupId>build.buf</groupId>
-            <artifactId>protovalidate</artifactId>
-            <version>0.1.9</version>
-        </dependency>
-        <dependency>
-            <groupId>io.grpc</groupId>
-            <artifactId>grpc-protobuf</artifactId>
-       </dependency>
-        <dependency>
-            <groupId>io.grpc</groupId>
-            <artifactId>grpc-stub</artifactId>
-        </dependency>
-    </dependencies>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-antrun-plugin</artifactId>
-                <version>3.1.0</version>
-                <executions>
-                    <execution>
-                        <id>generateSources</id>
-                        <phase>generate-sources</phase>
-                        <configuration>
-                            <target>
-                                <exec executable="rm">
-                                    <arg value="-rf" />
-                                    <arg value="src/main/protogen" />
-                                </exec>
-                                <exec executable="buf" dir="../">
-                                    <arg value="generate" />
-                                    <arg value="https://github.com/opentdf/platform.git#branch=main,subdir=service" />
-                                </exec>
-                                <exec executable="buf" dir="../">
-                                    <arg value="generate" />
-                                    <arg value="buf.build/grpc-ecosystem/grpc-gateway" />
-                                    <arg value="-o" />
-                                    <arg value="tmp-gen"/>
-                                </exec>
-                                <exec executable="cp" dir="../">
-                                    <arg value="-r" />
-                                    <arg value="tmp-gen/protocol/src/main/protogen/grpc"/>
-                                    <arg value="protocol/src/main/protogen"/>
-                                </exec>
-                                <exec executable="rm" dir="../">
-                                    <arg value="-rf" />
-                                    <arg value="tmp-gen"/>
-                                </exec>
-                            </target>
-                        </configuration>
-                        <goals>
-                            <goal>run</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <version>3.5.0</version>
-                <executions>
-                    <execution>
-                        <id>add-source</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>src/main/protogen</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/release-please.json b/release-please.json
index 1df29bb8..aaa7732d 100644
--- a/release-please.json
+++ b/release-please.json
@@ -1,6 +1,6 @@
 {
   "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
-  "release-type": "java-yoshi-mono-repo",
+  "release-type": "maven",
   "bump-minor-pre-major": true,
   "bump-patch-for-minor-pre-major": true,
   "separate-pull-requests": false,
@@ -9,4 +9,4 @@
   "packages": {
     ".": {}
   }
-}
+}
\ No newline at end of file
diff --git a/protocol/buf.lock b/sdk/buf.lock
similarity index 100%
rename from protocol/buf.lock
rename to sdk/buf.lock
diff --git a/protocol/buf.yaml b/sdk/buf.yaml
similarity index 100%
rename from protocol/buf.yaml
rename to sdk/buf.yaml
diff --git a/sdk/pom.xml b/sdk/pom.xml
index 05c3f19b..20a48594 100644
--- a/sdk/pom.xml
+++ b/sdk/pom.xml
@@ -1,22 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <name>sdk</name>
     <artifactId>sdk</artifactId>
     <parent>
         <artifactId>sdk-pom</artifactId>
         <groupId>io.opentdf.platform</groupId>
-        <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
+        <version>${revision}</version>
     </parent>
     <packaging>jar</packaging>
     <dependencies>
-        <dependency>
-            <groupId>io.opentdf.platform</groupId>
-            <artifactId>protocol</artifactId>
-            <version>0.6.2-SNAPSHOT</version><!-- {x-version-update:java-sdk:current} -->
-        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
@@ -28,7 +24,7 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-        <groupId>org.apache.logging.log4j</groupId>
+            <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-core</artifactId>
             <scope>test</scope>
         </dependency>
@@ -135,5 +131,75 @@
             <groupId>org.mockito</groupId>
             <artifactId>mockito-junit-jupiter</artifactId>
         </dependency>
+        <dependency>
+            <groupId>build.buf</groupId>
+            <artifactId>protovalidate</artifactId>
+            <version>0.1.9</version>
+        </dependency>
     </dependencies>
-</project>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>3.1.0</version>
+                <executions>
+                    <execution>
+                        <id>generateSources</id>
+                        <phase>generate-sources</phase>
+                        <configuration>
+                            <target>
+                                <exec executable="rm">
+                                    <arg value="-rf" />
+                                    <arg value="src/main/protogen" />
+                                </exec>
+                                <exec executable="buf" dir="../">
+                                    <arg value="generate" />
+                                    <arg
+                                        value="https://github.com/opentdf/platform.git#branch=main,subdir=service" />
+                                </exec>
+                                <exec executable="buf" dir="../">
+                                    <arg value="generate" />
+                                    <arg value="buf.build/grpc-ecosystem/grpc-gateway" />
+                                    <arg value="-o" />
+                                    <arg value="tmp-gen" />
+                                </exec>
+                                <exec executable="cp" dir="../">
+                                    <arg value="-r" />
+                                    <arg value="tmp-gen/sdk/src/main/protogen/grpc" />
+                                    <arg value="sdk/src/main/protogen" />
+                                </exec>
+                                <exec executable="rm" dir="../">
+                                    <arg value="-rf" />
+                                    <arg value="tmp-gen" />
+                                </exec>
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>3.5.0</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>src/main/protogen</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/AssertionConfig.java b/sdk/src/main/java/io/opentdf/platform/sdk/AssertionConfig.java
index 6a8c229c..510a008c 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/AssertionConfig.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/AssertionConfig.java
@@ -1,10 +1,8 @@
 package io.opentdf.platform.sdk;
 
-import com.nimbusds.jose.JWSSigner;
 
 import java.util.Objects;
 
-
 public class AssertionConfig {
 
     public enum Type {
@@ -70,7 +68,7 @@ public AssertionKey(AssertionKeyAlg alg, Object key) {
             this.key = key;
         }
 
-        public boolean isDefined()  {
+        public boolean isDefined() {
             return alg != AssertionKeyAlg.NotDefined;
         }
     }
@@ -82,10 +80,13 @@ static public class Statement {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
             Statement statement = (Statement) o;
-            return Objects.equals(format, statement.format) && Objects.equals(schema, statement.schema) && Objects.equals(value, statement.value);
+            return Objects.equals(format, statement.format) && Objects.equals(schema, statement.schema)
+                    && Objects.equals(value, statement.value);
         }
 
         @Override
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java b/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java
index 29b7c4d5..5e9eb7da 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java
@@ -45,7 +45,6 @@ class RuleType {
     public static final String EMPTY_TERM = "DEFAULT";
 }
 
-
 public class Autoconfigure {
 
     public static Logger logger = LoggerFactory.getLogger(Autoconfigure.class);
@@ -73,7 +72,7 @@ public boolean equals(Object obj) {
                 return false;
             }
             KeySplitStep ss = (KeySplitStep) obj;
-            if ((this.kas.equals(ss.kas)) && (this.splitID.equals(ss.splitID))){
+            if ((this.kas.equals(ss.kas)) && (this.splitID.equals(ss.splitID))) {
                 return true;
             }
             return false;
@@ -185,7 +184,7 @@ public boolean equals(Object obj) {
                 return false;
             }
             AttributeValueFQN afqn = (AttributeValueFQN) obj;
-            if (this.key.equals(afqn.key)){
+            if (this.key.equals(afqn.key)) {
                 return true;
             }
             return false;
@@ -264,8 +263,8 @@ public Granter(List<AttributeValueFQN> policy) {
             this.policy = policy;
         }
 
-        public  Map<String, KeyAccessGrant> getGrants() {
-            return new HashMap<String,KeyAccessGrant>(grants);
+        public Map<String, KeyAccessGrant> getGrants() {
+            return new HashMap<String, KeyAccessGrant>(grants);
         }
 
         public List<AttributeValueFQN> getPolicy() {
@@ -273,8 +272,7 @@ public List<AttributeValueFQN> getPolicy() {
         }
 
         public void addGrant(AttributeValueFQN fqn, String kas, Attribute attr) {
-            grants.computeIfAbsent(fqn.key, k -> new KeyAccessGrant(attr, new ArrayList<>()))
-                .kases.add(kas);
+            grants.computeIfAbsent(fqn.key, k -> new KeyAccessGrant(attr, new ArrayList<>())).kases.add(kas);
         }
 
         public void addAllGrants(AttributeValueFQN fqn, List<KeyAccessServer> gs, Attribute attr) {
@@ -293,8 +291,8 @@ public KeyAccessGrant byAttribute(AttributeValueFQN fqn) {
             return grants.get(fqn.key);
         }
 
-
-        public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSplitID) throws AutoConfigureException {
+        public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSplitID)
+                throws AutoConfigureException {
             AttributeBooleanExpression b = constructAttributeBoolean();
             BooleanKeyExpression k = insertKeysForAttribute(b);
             if (k == null) {
@@ -330,35 +328,35 @@ public List<KeySplitStep> plan(List<String> defaultKas, Supplier<String> genSpli
 
         BooleanKeyExpression insertKeysForAttribute(AttributeBooleanExpression e) throws AutoConfigureException {
             List<KeyClause> kcs = new ArrayList<>(e.must.size());
-    
+
             for (SingleAttributeClause clause : e.must) {
                 List<PublicKeyInfo> kcv = new ArrayList<>(clause.values.size());
-    
+
                 for (AttributeValueFQN term : clause.values) {
                     KeyAccessGrant grant = byAttribute(term);
                     if (grant == null) {
                         throw new AutoConfigureException(String.format("no definition or grant found for [%s]", term));
                     }
-    
+
                     List<String> kases = grant.kases;
                     if (kases.isEmpty()) {
                         kases = List.of(RuleType.EMPTY_TERM);
                     }
-    
+
                     for (String kas : kases) {
                         kcv.add(new PublicKeyInfo(kas));
                     }
                 }
-    
+
                 String op = ruleToOperator(clause.def.getRule());
                 if (op == RuleType.UNSPECIFIED) {
                     logger.warn("Unknown attribute rule type: " + clause);
                 }
-    
+
                 KeyClause kc = new KeyClause(op, kcv);
                 kcs.add(kc);
             }
-    
+
             return new BooleanKeyExpression(kcs);
         }
 
@@ -371,7 +369,8 @@ AttributeBooleanExpression constructAttributeBoolean() throws AutoConfigureExcep
                 if (clause != null) {
                     clause.values.add(aP);
                 } else if (byAttribute(aP) != null) {
-                    var x = new SingleAttributeClause(byAttribute(aP).attr, new ArrayList<AttributeValueFQN>(Arrays.asList(aP)));
+                    var x = new SingleAttributeClause(byAttribute(aP).attr,
+                            new ArrayList<AttributeValueFQN>(Arrays.asList(aP)));
                     prefixes.put(a.getKey(), x);
                     sortedPrefixes.add(a.getKey());
                 }
@@ -384,34 +383,33 @@ AttributeBooleanExpression constructAttributeBoolean() throws AutoConfigureExcep
             return new AttributeBooleanExpression(must);
         }
 
-
-
         static class AttributeMapping {
 
             private Map<AttributeNameFQN, Attribute> dict;
-        
+
             public AttributeMapping() {
                 this.dict = new HashMap<>();
             }
-        
+
             public void put(Attribute ad) throws AutoConfigureException {
                 if (this.dict == null) {
                     this.dict = new HashMap<>();
                 }
-        
+
                 AttributeNameFQN prefix = new AttributeNameFQN(ad.getFqn());
-        
+
                 if (this.dict.containsKey(prefix)) {
                     throw new AutoConfigureException("Attribute prefix already found: [" + prefix.toString() + "]");
                 }
-        
+
                 this.dict.put(prefix, ad);
             }
-        
+
             public Attribute get(AttributeNameFQN prefix) throws AutoConfigureException {
                 Attribute ad = this.dict.get(prefix);
                 if (ad == null) {
-                    throw new AutoConfigureException("Unknown attribute type: [" + prefix.toString() + "], not in [" + this.dict.keySet().toString() + "]");
+                    throw new AutoConfigureException("Unknown attribute type: [" + prefix.toString() + "], not in ["
+                            + this.dict.keySet().toString() + "]");
                 }
                 return ad;
             }
@@ -422,7 +420,7 @@ static class SingleAttributeClause {
 
             private Attribute def;
             private List<AttributeValueFQN> values;
-        
+
             public SingleAttributeClause(Attribute def, List<AttributeValueFQN> values) {
                 this.def = def;
                 this.values = values;
@@ -432,24 +430,24 @@ public SingleAttributeClause(Attribute def, List<AttributeValueFQN> values) {
         class AttributeBooleanExpression {
 
             private List<SingleAttributeClause> must;
-        
+
             public AttributeBooleanExpression(List<SingleAttributeClause> must) {
                 this.must = must;
             }
-        
+
             @Override
             public String toString() {
                 if (must == null || must.isEmpty()) {
                     return "∅";
                 }
-        
+
                 StringBuilder sb = new StringBuilder();
                 for (int i = 0; i < must.size(); i++) {
                     SingleAttributeClause clause = must.get(i);
                     if (i > 0) {
                         sb.append("&");
                     }
-        
+
                     List<AttributeValueFQN> values = clause.values;
                     if (values == null || values.isEmpty()) {
                         sb.append(clause.def.getFqn());
@@ -458,7 +456,7 @@ public String toString() {
                     } else {
                         sb.append(clause.def.getFqn());
                         sb.append("/value/{");
-        
+
                         StringJoiner joiner = new StringJoiner(",");
                         for (AttributeValueFQN v : values) {
                             joiner.add(v.value());
@@ -469,20 +467,20 @@ public String toString() {
                 }
                 return sb.toString();
             }
-        
+
         }
 
         public class PublicKeyInfo {
             private String kas;
-        
+
             public PublicKeyInfo(String kas) {
                 this.kas = kas;
             }
-        
+
             public String getKas() {
                 return kas;
             }
-        
+
             public void setKas(String kas) {
                 this.kas = kas;
             }
@@ -491,12 +489,12 @@ public void setKas(String kas) {
         public class KeyClause {
             private String operator;
             private List<PublicKeyInfo> values;
-        
+
             public KeyClause(String operator, List<PublicKeyInfo> values) {
                 this.operator = operator;
                 this.values = values;
             }
-        
+
             @Override
             public String toString() {
                 if (values.size() == 1 && values.get(0).getKas().equals(RuleType.EMPTY_TERM)) {
@@ -505,14 +503,14 @@ public String toString() {
                 if (values.size() == 1) {
                     return "(" + values.get(0).getKas() + ")";
                 }
-        
+
                 StringBuilder sb = new StringBuilder();
                 sb.append("(");
                 String op = "⋀";
                 if (operator.equals(RuleType.ANY_OF)) {
                     op = "⋁";
                 }
-        
+
                 for (int i = 0; i < values.size(); i++) {
                     if (i > 0) {
                         sb.append(op);
@@ -520,18 +518,18 @@ public String toString() {
                     sb.append(values.get(i).getKas());
                 }
                 sb.append(")");
-        
+
                 return sb.toString();
             }
         }
 
         public class BooleanKeyExpression {
             private List<KeyClause> values;
-        
+
             public BooleanKeyExpression(List<KeyClause> values) {
                 this.values = values;
             }
-        
+
             @Override
             public String toString() {
                 StringBuilder sb = new StringBuilder();
@@ -576,7 +574,7 @@ public BooleanKeyExpression reduce() {
                 if (conjunction.isEmpty()) {
                     return new BooleanKeyExpression(new ArrayList<>());
                 }
-        
+
                 List<KeyClause> newValues = new ArrayList<>();
                 for (List<String> d : conjunction) {
                     List<PublicKeyInfo> pki = new ArrayList<>();
@@ -591,7 +589,7 @@ public BooleanKeyExpression reduce() {
             public Disjunction sortedNoDupes(List<PublicKeyInfo> l) {
                 Set<String> set = new HashSet<>();
                 Disjunction list = new Disjunction();
-    
+
                 for (PublicKeyInfo e : l) {
                     String kas = e.getKas();
                     if (!kas.equals(RuleType.EMPTY_TERM) && !set.contains(kas)) {
@@ -599,7 +597,7 @@ public Disjunction sortedNoDupes(List<PublicKeyInfo> l) {
                         list.add(kas);
                     }
                 }
-    
+
                 Collections.sort(list);
                 return list;
             }
@@ -621,7 +619,7 @@ public boolean less(Disjunction r) {
                 }
                 return this.size() < r.size();
             }
-        
+
             public boolean equals(Object obj) {
                 if (this == obj) {
                     return true;
@@ -675,23 +673,25 @@ public static String ruleToOperator(AttributeRuleTypeEnum e) {
     }
 
     // Gets a list of directory of KAS grants for a list of attribute FQNs
-    public static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException, InterruptedException, ExecutionException {
+    public static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache,
+            AttributeValueFQN... fqns) throws AutoConfigureException, InterruptedException, ExecutionException {
         String[] fqnsStr = new String[fqns.length];
         for (int i = 0; i < fqns.length; i++) {
             fqnsStr[i] = fqns[i].toString();
         }
 
         GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder()
-            .addAllFqns(Arrays.asList(fqnsStr))
-            .setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build())
-            .build();
+                .addAllFqns(Arrays.asList(fqnsStr))
+                .setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build())
+                .build();
 
         GetAttributeValuesByFqnsResponse av;
         av = as.getAttributeValuesByFqns(request).get();
 
         Granter grants = new Granter(Arrays.asList(fqns));
 
-        for (Map.Entry<String,GetAttributeValuesByFqnsResponse.AttributeAndValue> entry : av.getFqnAttributeValuesMap().entrySet()) {
+        for (Map.Entry<String, GetAttributeValuesByFqnsResponse.AttributeAndValue> entry : av.getFqnAttributeValuesMap()
+                .entrySet()) {
             String fqnstr = entry.getKey();
             AttributeAndValue pair = entry.getValue();
 
@@ -708,10 +708,10 @@ public static Granter newGranterFromService(AttributesServiceFutureStub as, KASK
                 grants.addAllGrants(fqn, v.getGrantsList(), def);
                 storeKeysToCache(v.getGrantsList(), keyCache);
             } else {
-              if (def != null) {
-                  grants.addAllGrants(fqn, def.getGrantsList(), def);
-                  storeKeysToCache(def.getGrantsList(), keyCache);
-              }
+                if (def != null) {
+                    grants.addAllGrants(fqn, def.getGrantsList(), def);
+                    storeKeysToCache(def.getGrantsList(), keyCache);
+                }
             }
         }
 
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Config.java b/sdk/src/main/java/io/opentdf/platform/sdk/Config.java
index 591dbe4d..a8766820 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/Config.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/Config.java
@@ -67,7 +67,6 @@ public String toString() {
         }
     }
 
-
     public static class AssertionVerificationKeys {
         public AssertionConfig.AssertionKey defaultKey;
         public Map<String, AssertionConfig.AssertionKey> keys = new HashMap<>();
@@ -100,7 +99,8 @@ public static TDFReaderConfig newTDFReaderConfig(Consumer<TDFReaderConfig>... op
         return config;
     }
 
-    public static Consumer<TDFReaderConfig> withAssertionVerificationKeys(AssertionVerificationKeys assertionVerificationKeys) {
+    public static Consumer<TDFReaderConfig> withAssertionVerificationKeys(
+            AssertionVerificationKeys assertionVerificationKeys) {
         return (TDFReaderConfig config) -> config.assertionVerificationKeys = assertionVerificationKeys;
     }
 
@@ -147,7 +147,7 @@ public static TDFConfig newTDFConfig(Consumer<TDFConfig>... options) {
 
     public static Consumer<TDFConfig> withDataAttributes(String... attributes) throws AutoConfigureException {
         List<Autoconfigure.AttributeValueFQN> attrValFqns = new ArrayList<Autoconfigure.AttributeValueFQN>();
-        for (String a : attributes){
+        for (String a : attributes) {
             Autoconfigure.AttributeValueFQN attrValFqn = new Autoconfigure.AttributeValueFQN(a);
             attrValFqns.add(attrValFqn);
         }
@@ -159,7 +159,7 @@ public static Consumer<TDFConfig> withDataAttributes(String... attributes) throw
 
     public static Consumer<TDFConfig> withDataAttributeValues(String... attributes) throws AutoConfigureException {
         List<Autoconfigure.AttributeValueFQN> attrValFqns = new ArrayList<Autoconfigure.AttributeValueFQN>();
-        for (String a : attributes){
+        for (String a : attributes) {
             Autoconfigure.AttributeValueFQN attrValFqn = new Autoconfigure.AttributeValueFQN(a);
             attrValFqns.add(attrValFqn);
         }
@@ -169,8 +169,10 @@ public static Consumer<TDFConfig> withDataAttributeValues(String... attributes)
         };
     }
 
-    // WithDataAttributeValues appends the given data attributes to the bound policy.
-    // Unlike `WithDataAttributes`, this will not trigger an attribute definition lookup
+    // WithDataAttributeValues appends the given data attributes to the bound
+    // policy.
+    // Unlike `WithDataAttributes`, this will not trigger an attribute definition
+    // lookup
     // during autoconfigure. That is, to use autoconfigure in an 'offline' context,
     // you must first store the relevant attribute information locally and load
     // it to the `CreateTDF` method with this option.
@@ -222,9 +224,9 @@ public static Consumer<TDFConfig> withAutoconfigure(boolean enable) {
         };
     }
 
-//    public static Consumer<TDFConfig> withDisableEncryption() {
-//        return (TDFConfig config) -> config.enableEncryption = false;
-//    }
+    // public static Consumer<TDFConfig> withDisableEncryption() {
+    // return (TDFConfig config) -> config.enableEncryption = false;
+    // }
 
     public static Consumer<TDFConfig> withMimeType(String mimeType) {
         return (TDFConfig config) -> config.mimeType = mimeType;
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java b/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java
index 3cd9da3a..4732865b 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java
@@ -30,7 +30,7 @@
 
 import static java.lang.String.format;
 
-public class KASClient implements SDK.KAS, AutoCloseable {
+public class KASClient implements SDK.KAS {
 
     private final Function<String, ManagedChannel> channelFactory;
     private final RSASSASigner signer;
@@ -41,10 +41,12 @@ public class KASClient implements SDK.KAS, AutoCloseable {
 
     /***
      * A client that communicates with KAS
-     * @param channelFactory A function that produces channels that can be used to communicate
+     * 
+     * @param channelFactory A function that produces channels that can be used to
+     *                       communicate
      * @param dpopKey
      */
-    public KASClient(Function <String, ManagedChannel> channelFactory, RSAKey dpopKey) {
+    public KASClient(Function<String, ManagedChannel> channelFactory, RSAKey dpopKey) {
         this.channelFactory = channelFactory;
         try {
             this.signer = new RSASSASigner(dpopKey);
@@ -61,7 +63,8 @@ public KASClient(Function <String, ManagedChannel> channelFactory, RSAKey dpopKe
     @Override
     public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) {
         var r = getStub(kasInfo.URL)
-                .publicKey(PublicKeyRequest.newBuilder().setAlgorithm(String.format("ec:%s", curve.toString())).build());
+                .publicKey(
+                        PublicKeyRequest.newBuilder().setAlgorithm(String.format("ec:%s", curve.toString())).build());
         var k2 = kasInfo.clone();
         k2.KID = r.getKid();
         k2.PublicKey = r.getPublicKey();
@@ -75,7 +78,7 @@ public Config.KASInfo getPublicKey(Config.KASInfo kasInfo) {
             return cachedValue;
         }
         PublicKeyResponse resp = getStub(kasInfo.URL).publicKey(PublicKeyRequest.getDefaultInstance());
-        
+
         var kiCopy = new Config.KASInfo();
         kiCopy.KID = resp.getKid();
         kiCopy.PublicKey = resp.getPublicKey();
@@ -87,7 +90,7 @@ public Config.KASInfo getPublicKey(Config.KASInfo kasInfo) {
     }
 
     @Override
-    public KASKeyCache getKeyCache(){
+    public KASKeyCache getKeyCache() {
         return this.kasKeyCache;
     }
 
@@ -122,7 +125,7 @@ private String normalizeAddress(String urlString) {
     public synchronized void close() {
         var entries = new ArrayList<>(stubs.values());
         stubs.clear();
-        for (var entry: entries) {
+        for (var entry : entries) {
             entry.channel.shutdownNow();
         }
     }
@@ -179,7 +182,7 @@ public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy) {
         return decryptor.decrypt(wrappedKey);
     }
 
-    public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL)  {
+    public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL) {
         ECKeyPair keyPair = new ECKeyPair(curve.toString(), ECKeyPair.ECAlgorithm.ECDH);
 
         NanoTDFKeyAccess keyAccess = new NanoTDFKeyAccess();
@@ -190,7 +193,7 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas
 
         NanoTDFRewrapRequestBody body = new NanoTDFRewrapRequestBody();
         body.algorithm = String.format("ec:%s", curve.toString());
-        body.clientPublicKey =  keyPair.publicKeyInPEMFormat();
+        body.clientPublicKey = keyPair.publicKeyInPEMFormat();
         body.keyAccess = keyAccess;
 
         var requestBody = gson.toJson(body);
@@ -236,9 +239,11 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas
     }
 
     private final HashMap<String, CacheEntry> stubs = new HashMap<>();
+
     private static class CacheEntry {
         final ManagedChannel channel;
         final AccessServiceGrpc.AccessServiceBlockingStub stub;
+
         private CacheEntry(ManagedChannel channel, AccessServiceGrpc.AccessServiceBlockingStub stub) {
             this.channel = channel;
             this.stub = stub;
@@ -257,4 +262,3 @@ synchronized AccessServiceGrpc.AccessServiceBlockingStub getStub(String url) {
         return stubs.get(realAddress).stub;
     }
 }
-
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 27837fbd..831274e2 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java
@@ -21,7 +21,6 @@
 import java.security.interfaces.RSAPublicKey;
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Base64;
 import java.util.List;
 import java.util.Objects;
 
@@ -32,10 +31,13 @@ public class Manifest {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        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);
+        return Objects.equals(encryptionInformation, manifest.encryptionInformation)
+                && Objects.equals(payload, manifest.payload) && Objects.equals(assertions, manifest.assertions);
     }
 
     @Override
@@ -45,7 +47,8 @@ public int hashCode() {
 
     private static class PolicyBindingSerializer implements JsonDeserializer<Object>, JsonSerializer<Object> {
         @Override
-        public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+        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()) {
@@ -60,6 +63,7 @@ public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContex
             return context.serialize(src, typeOfSrc);
         }
     }
+
     static public class Segment {
         public String hash;
         public long segmentSize;
@@ -67,10 +71,13 @@ static public class Segment {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            return segmentSize == segment.segmentSize && encryptedSegmentSize == segment.encryptedSegmentSize
+                    && Objects.equals(hash, segment.hash);
         }
 
         @Override
@@ -87,8 +94,10 @@ static public class RootSignature {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
         }
@@ -108,26 +117,34 @@ static public class IntegrityInformation {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            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);
+            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;
+            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);
         }
@@ -153,10 +170,16 @@ static public class KeyAccess {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            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
@@ -172,10 +195,13 @@ static public class Method {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            return Objects.equals(algorithm, method.algorithm) && Objects.equals(iv, method.iv)
+                    && Objects.equals(IsStreamable, method.IsStreamable);
         }
 
         @Override
@@ -184,8 +210,6 @@ public int hashCode() {
         }
     }
 
-    
-
     static public class EncryptionInformation {
         @SerializedName(value = "type")
         public String keyAccessType;
@@ -198,10 +222,14 @@ static public class EncryptionInformation {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            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
@@ -219,10 +247,14 @@ static public class Payload {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            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);
+            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
@@ -237,8 +269,10 @@ static public class Binding {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
             Binding binding = (Binding) o;
             return Objects.equals(method, binding.method) && Objects.equals(signature, binding.signature);
         }
@@ -266,15 +300,21 @@ public HashValues(String assertionHash, String signature) {
                 this.signature = signature;
             }
 
-            public String getAssertionHash() { return assertionHash; }
-            public String getSignature() { return signature; }
-        }
+            public String getAssertionHash() {
+                return assertionHash;
+            }
 
+            public String getSignature() {
+                return signature;
+            }
+        }
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
             Assertion that = (Assertion) o;
             return Objects.equals(id, that.id) && Objects.equals(type, that.type) &&
                     Objects.equals(scope, that.scope) && Objects.equals(appliesToState, that.appliesToState) &&
@@ -303,7 +343,8 @@ public String hash() throws IOException {
         // Sign the assertion with the given hash and signature using the key.
         // It returns an error if the signing fails.
         // The assertion binding is updated with the method and the signature.
-        public void sign(final HashValues hashValues, final AssertionConfig.AssertionKey assertionKey) throws KeyLengthException {
+        public void sign(final HashValues hashValues, final AssertionConfig.AssertionKey assertionKey)
+                throws KeyLengthException {
             // Build JWT claims
             final JWTClaimsSet claims = new JWTClaimsSet.Builder()
                     .claim(kAssertionHash, hashValues.assertionHash)
@@ -327,8 +368,10 @@ public void sign(final HashValues hashValues, final AssertionConfig.AssertionKey
         }
 
         // Checks the binding signature of the assertion and
-        // returns the hash and the signature. It returns an error if the verification fails.
-        public Assertion.HashValues verify(AssertionConfig.AssertionKey assertionKey) throws ParseException, JOSEException {
+        // returns the hash and the signature. It returns an error if the verification
+        // fails.
+        public Assertion.HashValues verify(AssertionConfig.AssertionKey assertionKey)
+                throws ParseException, JOSEException {
             if (binding == null) {
                 throw new SDKException("Binding is null in assertion");
             }
@@ -350,7 +393,8 @@ public Assertion.HashValues verify(AssertionConfig.AssertionKey assertionKey) th
             return new Assertion.HashValues(assertionHash, signature);
         }
 
-        private SignedJWT createSignedJWT(final JWTClaimsSet claims, final AssertionConfig.AssertionKey assertionKey) throws SDKException {
+        private SignedJWT createSignedJWT(final JWTClaimsSet claims, final AssertionConfig.AssertionKey assertionKey)
+                throws SDKException {
             final JWSHeader jwsHeader;
             switch (assertionKey.alg) {
                 case RS256:
@@ -366,7 +410,8 @@ private SignedJWT createSignedJWT(final JWTClaimsSet claims, final AssertionConf
             return new SignedJWT(jwsHeader, claims);
         }
 
-        private JWSSigner createSigner(final AssertionConfig.AssertionKey assertionKey) throws SDKException, KeyLengthException {
+        private JWSSigner createSigner(final AssertionConfig.AssertionKey assertionKey)
+                throws SDKException, KeyLengthException {
             switch (assertionKey.alg) {
                 case RS256:
                     if (!(assertionKey.key instanceof PrivateKey)) {
@@ -397,5 +442,5 @@ private JWSVerifier createVerifier(AssertionConfig.AssertionKey assertionKey) th
 
     public EncryptionInformation encryptionInformation;
     public Payload payload;
-    public  List<Assertion> assertions = new ArrayList<>();
+    public List<Assertion> assertions = new ArrayList<>();
 }
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 168f6a69..9132e570 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java
@@ -15,16 +15,17 @@
 import org.bouncycastle.jce.interfaces.ECPublicKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
 public class NanoTDF {
 
     public static Logger logger = LoggerFactory.getLogger(NanoTDF.class);
 
-    public static final byte[] MAGIC_NUMBER_AND_VERSION = new byte[]{0x4C, 0x31, 0x4C};
-    private static final int kMaxTDFSize = ((16 * 1024 * 1024) - 3 - 32);  // 16 mb - 3(iv) - 32(max auth tag)
+    public static final byte[] MAGIC_NUMBER_AND_VERSION = new byte[] { 0x4C, 0x31, 0x4C };
+    private static final int kMaxTDFSize = ((16 * 1024 * 1024) - 3 - 32); // 16 mb - 3(iv) - 32(max auth tag)
     private static final int kNanoTDFGMACLength = 8;
     private static final int kIvPadding = 9;
     private static final int kNanoTDFIvSize = 3;
-    private static final byte[] kEmptyIV = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+    private static final byte[] kEmptyIV = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
 
     public static class NanoTDFMaxSizeLimit extends Exception {
         public NanoTDFMaxSizeLimit(String errorMessage) {
@@ -45,8 +46,8 @@ public InvalidNanoTDFConfig(String errorMessage) {
     }
 
     public int createNanoTDF(ByteBuffer data, OutputStream outputStream,
-                             Config.NanoTDFConfig nanoTDFConfig,
-                             SDK.KAS kas) throws IOException, NanoTDFMaxSizeLimit, InvalidNanoTDFConfig,
+            Config.NanoTDFConfig nanoTDFConfig,
+            SDK.KAS kas) throws IOException, NanoTDFMaxSizeLimit, InvalidNanoTDFConfig,
             NoSuchAlgorithmException, UnsupportedNanoTDFFeature {
 
         int nanoTDFSize = 0;
@@ -137,7 +138,7 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream,
 
         // Write the length of the payload as int24
         int cipherDataLengthWithoutPadding = cipherData.length - kIvPadding;
-        byte[] bgIntAsBytes =  ByteBuffer.allocate(4).putInt(cipherDataLengthWithoutPadding).array();
+        byte[] bgIntAsBytes = ByteBuffer.allocate(4).putInt(cipherDataLengthWithoutPadding).array();
         outputStream.write(bgIntAsBytes, 1, 3);
         nanoTDFSize += 3;
 
@@ -151,7 +152,7 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream,
     }
 
     public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream,
-                            SDK.KAS kas) throws IOException {
+            SDK.KAS kas) throws IOException {
 
         Header header = new Header(nanoTDF);
 
@@ -164,7 +165,7 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream,
 
         String kasUrl = header.getKasLocator().getResourceUrl();
 
-        byte[] key =  kas.unwrapNanoTDF(header.getECCMode().getEllipticCurveType(),
+        byte[] key = kas.unwrapNanoTDF(header.getECCMode().getEllipticCurveType(),
                 base64HeaderData,
                 kasUrl);
         logger.debug("readNanoTDF key is {}", Base64.getEncoder().encodeToString(key));
@@ -200,7 +201,7 @@ PolicyObject createPolicyObject(List<String> attributes) {
         policyObject.body.dataAttributes = new ArrayList<>();
         policyObject.body.dissem = new ArrayList<>();
 
-        for (String attribute: attributes) {
+        for (String attribute : attributes) {
             PolicyObject.AttributeObject attributeObject = new PolicyObject.AttributeObject();
             attributeObject.attribute = attribute;
             policyObject.body.dataAttributes.add(attributeObject);
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/PolicyObject.java b/sdk/src/main/java/io/opentdf/platform/sdk/PolicyObject.java
index 8b1bb33f..15d2d0bb 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/PolicyObject.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/PolicyObject.java
@@ -1,7 +1,6 @@
 package io.opentdf.platform.sdk;
 
 import java.util.List;
-import java.util.UUID;
 
 public class PolicyObject {
     static public class AttributeObject {
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
index dcde93ab..fe2a8005 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
@@ -22,8 +22,10 @@
 import java.util.Optional;
 
 /**
- * The SDK class represents a software development kit for interacting with the opentdf platform. It
- * provides various services and stubs for making API calls to the opentdf platform.
+ * The SDK class represents a software development kit for interacting with the
+ * opentdf platform. It
+ * provides various services and stubs for making API calls to the opentdf
+ * platform.
  */
 public class SDK implements AutoCloseable {
     private final Services services;
@@ -39,19 +41,28 @@ public void close() throws Exception {
 
     public interface KAS extends AutoCloseable {
         Config.KASInfo getPublicKey(Config.KASInfo kasInfo);
+
         Config.KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve);
+
         byte[] unwrap(Manifest.KeyAccess keyAccess, String policy);
+
         byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL);
+
         KASKeyCache getKeyCache();
     }
 
     // TODO: add KAS
     public interface Services extends AutoCloseable {
         AuthorizationServiceFutureStub authorization();
+
         AttributesServiceFutureStub attributes();
+
         NamespaceServiceFutureStub namespaces();
+
         SubjectMappingServiceFutureStub subjectMappings();
+
         ResourceMappingServiceFutureStub resourceMappings();
+
         KAS kas();
 
         static Services newServices(ManagedChannel channel, KAS kas) {
@@ -120,8 +131,10 @@ public Services getServices() {
     }
 
     /**
-     * Checks to see if this has the structure of a Z-TDF in that it is a zip file containing
+     * Checks to see if this has the structure of a Z-TDF in that it is a zip file
+     * containing
      * a `manifest.json` and a `0.payload`
+     * 
      * @param channel A channel containing the bytes of the potential Z-TDF
      * @return `true` if
      */
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
index ad156f42..be13bdd0 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
@@ -60,37 +60,37 @@ public SDKBuilder sslFactory(SSLFactory sslFactory) {
 
     /**
      * Add SSL Context with trusted certs from certDirPath
+     * 
      * @param certsDirPath Path to a directory containing .pem or .crt trusted certs
      * @return
      */
-    public SDKBuilder sslFactoryFromDirectory(String certsDirPath)  throws Exception{
+    public SDKBuilder sslFactoryFromDirectory(String certsDirPath) throws Exception {
         File certsDir = new File(certsDirPath);
-        File[] certFiles =
-                certsDir.listFiles((dir, name) -> name.endsWith(".pem") || name.endsWith(".crt"));
+        File[] certFiles = certsDir.listFiles((dir, name) -> name.endsWith(".pem") || name.endsWith(".crt"));
         logger.info("Loading certificates from: " + certsDir.getAbsolutePath());
         List<InputStream> certStreams = new ArrayList<>();
         for (File certFile : certFiles) {
             certStreams.add(new FileInputStream(certFile));
         }
-        X509ExtendedTrustManager trustManager =
-                PemUtils.loadTrustMaterial(certStreams.toArray(new InputStream[0]));
-        this.sslFactory =
-                SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
-                        .withTrustMaterial(trustManager).build();
+        X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(certStreams.toArray(new InputStream[0]));
+        this.sslFactory = SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
+                .withTrustMaterial(trustManager).build();
         return this;
     }
 
     /**
-     * Add SSL Context with default system trust material + certs contained in a Java keystore
-     * @param keystorePath Path to keystore
+     * Add SSL Context with default system trust material + certs contained in a
+     * Java keystore
+     * 
+     * @param keystorePath     Path to keystore
      * @param keystorePassword Password to keystore
      * @return
      */
     public SDKBuilder sslFactoryFromKeyStore(String keystorePath, String keystorePassword) {
-        this.sslFactory =
-                SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
-                        .withTrustMaterial(Path.of(keystorePath), keystorePassword==null ?
-                                "".toCharArray() : keystorePassword.toCharArray()).build();
+        this.sslFactory = SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
+                .withTrustMaterial(Path.of(keystorePath),
+                        keystorePassword == null ? "".toCharArray() : keystorePassword.toCharArray())
+                .build();
         return this;
     }
 
@@ -117,12 +117,14 @@ private GRPCAuthInterceptor getGrpcAuthInterceptor(RSAKey rsaKey) {
         }
 
         if (clientAuth == null) {
-            // this simplifies things for now, if we need to support this case we can revisit
+            // this simplifies things for now, if we need to support this case we can
+            // revisit
             throw new SDKException("cannot build an SDK without specifying OAuth credentials");
         }
 
-        // we don't add the auth listener to this channel since it is only used to call the
-        //    well known endpoint
+        // we don't add the auth listener to this channel since it is only used to call
+        // the
+        // well known endpoint
         ManagedChannel bootstrapChannel = null;
         GetWellKnownConfigurationResponse config;
         try {
@@ -148,7 +150,9 @@ private GRPCAuthInterceptor getGrpcAuthInterceptor(RSAKey rsaKey) {
                     .getStringValue();
 
         } catch (IllegalArgumentException e) {
-            logger.warn("no `platform_issuer` found in well known configuration. requests from the SDK will be unauthenticated", e);
+            logger.warn(
+                    "no `platform_issuer` found in well known configuration. requests from the SDK will be unauthenticated",
+                    e);
             return null;
         }
 
@@ -156,7 +160,7 @@ private GRPCAuthInterceptor getGrpcAuthInterceptor(RSAKey rsaKey) {
         OIDCProviderMetadata providerMetadata;
         try {
             providerMetadata = OIDCProviderMetadata.resolve(issuer, httpRequest -> {
-                if (sslFactory!=null) {
+                if (sslFactory != null) {
                     httpRequest.setSSLSocketFactory(sslFactory.getSslSocketFactory());
                 }
             });
@@ -200,14 +204,14 @@ ServicesAndInternals buildServices() {
 
         } else {
             channel = getManagedChannelBuilder(platformEndpoint).intercept(authInterceptor).build();
-            managedChannelFactory = (String endpoint) -> getManagedChannelBuilder(endpoint).intercept(authInterceptor).build();
+            managedChannelFactory = (String endpoint) -> getManagedChannelBuilder(endpoint).intercept(authInterceptor)
+                    .build();
         }
         var client = new KASClient(managedChannelFactory, dpopKey);
         return new ServicesAndInternals(
                 authInterceptor,
                 sslFactory == null ? null : sslFactory.getTrustManager().orElse(null),
-                SDK.Services.newServices(channel, client)
-        );
+                SDK.Services.newServices(channel, client));
     }
 
     public SDK build() {
@@ -216,9 +220,12 @@ public SDK build() {
     }
 
     /**
-     * This produces a channel configured with all the available SDK options. The only
-     * reason it can't take in an interceptor is because we need to create a channel that
+     * This produces a channel configured with all the available SDK options. The
+     * only
+     * reason it can't take in an interceptor is because we need to create a channel
+     * that
      * doesn't have any authentication when we are bootstrapping
+     * 
      * @param endpoint The endpoint that we are creating the channel for
      * @return {@type ManagedChannelBuilder<?>} configured with the SDK options
      */
@@ -227,7 +234,7 @@ private ManagedChannelBuilder<?> getManagedChannelBuilder(String endpoint) {
         if (sslFactory != null && !usePlainText) {
             channelBuilder = Grpc.newChannelBuilder(endpoint, TlsChannelCredentials.newBuilder()
                     .trustManager(sslFactory.getTrustManager().get()).build());
-        }else{
+        } else {
             channelBuilder = ManagedChannelBuilder.forTarget(endpoint);
         }
 
@@ -237,7 +244,7 @@ private ManagedChannelBuilder<?> getManagedChannelBuilder(String endpoint) {
         return channelBuilder;
     }
 
-    SSLFactory getSslFactory(){
+    SSLFactory getSslFactory() {
         return this.sslFactory;
     }
 }
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 41bba40b..e7c8aff5 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
@@ -1,12 +1,7 @@
 package io.opentdf.platform.sdk;
 
-
 import com.google.gson.Gson;
 import com.nimbusds.jose.*;
-import com.nimbusds.jose.crypto.MACVerifier;
-import com.nimbusds.jose.crypto.RSASSAVerifier;
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.nimbusds.jwt.SignedJWT;
 
 import io.opentdf.platform.policy.Value;
 import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub;
@@ -14,8 +9,6 @@
 import io.opentdf.platform.sdk.Autoconfigure.AttributeValueFQN;
 import io.opentdf.platform.sdk.Config.KASInfo;
 
-import com.nimbusds.jose.crypto.RSASSASigner;
-import com.nimbusds.jose.crypto.MACSigner;
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Hex;
 import org.erdtman.jcs.JsonCanonicalizer;
@@ -29,7 +22,6 @@
 import java.nio.channels.SeekableByteChannel;
 import java.nio.charset.StandardCharsets;
 import java.security.*;
-import java.util.function.Consumer;
 import java.text.ParseException;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
@@ -42,7 +34,8 @@ public TDF() {
         this(MAX_TDF_INPUT_SIZE);
     }
 
-    // constructor for tests so that we can set a maximum size that's tractable for tests
+    // constructor for tests so that we can set a maximum size that's tractable for
+    // tests
     TDF(long maximumInputSize) {
         this.maximumSize = maximumInputSize;
     }
@@ -54,7 +47,7 @@ public TDF() {
     private static final String kSplitKeyType = "split";
     private static final String kWrapped = "wrapped";
     private static final String kKasProtocol = "kas";
-    private static final int kGcmIvSize  = 12;
+    private static final int kGcmIvSize = 12;
     private static final int kAesBlockSize = 16;
     private static final String kGCMCipherAlgorithm = "AES-256-GCM";
     private static final int kGMACPayloadLength = 16;
@@ -69,7 +62,7 @@ public TDF() {
 
     private static final Gson gson = new Gson();
 
-    public class SplitKeyException extends IOException { 
+    public class SplitKeyException extends IOException {
         public SplitKeyException(String errorMessage) {
             super(errorMessage);
         }
@@ -135,7 +128,6 @@ public TDFReadFailed(String errorMessage) {
         }
     }
 
-
     public static class EncryptedMetadata {
         private String ciphertext;
         private String iv;
@@ -162,7 +154,7 @@ PolicyObject createPolicyObject(List<Autoconfigure.AttributeValueFQN> attributes
             policyObject.body.dataAttributes = new ArrayList<>();
             policyObject.body.dissem = new ArrayList<>();
 
-            for (Autoconfigure.AttributeValueFQN attribute: attributes) {
+            for (Autoconfigure.AttributeValueFQN attribute : attributes) {
                 PolicyObject.AttributeObject attributeObject = new PolicyObject.AttributeObject();
                 attributeObject.attribute = attribute.toString();
                 policyObject.body.dataAttributes.add(attributeObject);
@@ -171,12 +163,14 @@ PolicyObject createPolicyObject(List<Autoconfigure.AttributeValueFQN> attributes
         }
 
         private static final Base64.Encoder encoder = Base64.getEncoder();
+
         private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
             manifest.encryptionInformation.keyAccessType = kSplitKeyType;
-            manifest.encryptionInformation.keyAccessObj =  new ArrayList<>();
+            manifest.encryptionInformation.keyAccessObj = new ArrayList<>();
 
             PolicyObject policyObject = createPolicyObject(tdfConfig.attributes);
-            String base64PolicyObject  = encoder.encodeToString(gson.toJson(policyObject).getBytes(StandardCharsets.UTF_8));
+            String base64PolicyObject = encoder
+                    .encodeToString(gson.toJson(policyObject).getBytes(StandardCharsets.UTF_8));
             List<byte[]> symKeys = new ArrayList<>();
             Map<String, Config.KASInfo> latestKASInfo = new HashMap<>();
             if (tdfConfig.splitPlan == null || tdfConfig.splitPlan.isEmpty()) {
@@ -197,7 +191,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
             }
 
             // Seed anything passed in manually
-            for (Config.KASInfo kasInfo: tdfConfig.kasInfoList) {
+            for (Config.KASInfo kasInfo : tdfConfig.kasInfoList) {
                 if (kasInfo.PublicKey != null && !kasInfo.PublicKey.isEmpty()) {
                     latestKASInfo.put(kasInfo.URL, kasInfo);
                 }
@@ -230,22 +224,22 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
                 }
             }
 
-            for (String splitID: splitIDs) {
+            for (String splitID : splitIDs) {
                 // Symmetric key
                 byte[] symKey = new byte[GCM_KEY_SIZE];
                 sRandom.nextBytes(symKey);
                 symKeys.add(symKey);
 
                 // Add policyBinding
-                var hexBinding = Hex.encodeHexString(CryptoUtils.CalculateSHA256Hmac(symKey, base64PolicyObject.getBytes(StandardCharsets.UTF_8)));
+                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));
-                
 
                 // Add meta data
                 var encryptedMetadata = new String();
-                if(tdfConfig.metaData != null && !tdfConfig.metaData.trim().isEmpty()) {
+                if (tdfConfig.metaData != null && !tdfConfig.metaData.trim().isEmpty()) {
                     AesGcm aesGcm = new AesGcm(symKey);
                     var encrypted = aesGcm.encrypt(tdfConfig.metaData.getBytes(StandardCharsets.UTF_8));
 
@@ -257,7 +251,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
                     encryptedMetadata = encoder.encodeToString(metadata.getBytes(StandardCharsets.UTF_8));
                 }
 
-                for (Config.KASInfo kasInfo: conjunction.get(splitID)){
+                for (Config.KASInfo kasInfo : conjunction.get(splitID)) {
                     if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) {
                         throw new KasPublicKeyMissing("Kas public key is missing in kas information list");
                     }
@@ -284,7 +278,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
             manifest.encryptionInformation.method.algorithm = kGCMCipherAlgorithm;
 
             // Create the payload key by XOR all the keys in key access object.
-            for (byte[] symKey: symKeys) {
+            for (byte[] symKey : symKeys) {
                 for (int index = 0; index < symKey.length; index++) {
                     this.payloadKey[index] ^= symKey[index];
                 }
@@ -295,10 +289,12 @@ private void prepareManifest(Config.TDFConfig tdfConfig, SDK.KAS kas) {
     }
 
     private static final Base64.Decoder decoder = Base64.getDecoder();
+
     public static class Reader {
         private final TDFReader tdfReader;
         private final byte[] payloadKey;
         private final Manifest manifest;
+
         public String getMetadata() {
             return unencryptedMetadata;
         }
@@ -324,8 +320,8 @@ public void readPayload(OutputStream outputStream) throws TDFReadFailed,
 
             MessageDigest digest = MessageDigest.getInstance("SHA-256");
 
-            for (Manifest.Segment segment: manifest.encryptionInformation.integrityInformation.segments) {
-                byte[] readBuf = new byte[(int)segment.encryptedSegmentSize];
+            for (Manifest.Segment segment : manifest.encryptionInformation.integrityInformation.segments) {
+                byte[] readBuf = new byte[(int) segment.encryptedSegmentSize];
                 int bytesRead = tdfReader.readPayloadBytes(readBuf);
 
                 if (readBuf.length != bytesRead) {
@@ -376,30 +372,33 @@ private static String calculateSignature(byte[] data, byte[] secret, Config.Inte
     }
 
     public TDFObject createTDF(InputStream payload,
-                               OutputStream outputStream,
-                               Config.TDFConfig tdfConfig, SDK.KAS kas, AttributesServiceFutureStub attrService) throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException {
+            OutputStream outputStream,
+            Config.TDFConfig tdfConfig, SDK.KAS kas, AttributesServiceFutureStub attrService)
+            throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException {
 
         if (tdfConfig.autoconfigure) {
             Autoconfigure.Granter granter = new Autoconfigure.Granter(new ArrayList<>());
             if (tdfConfig.attributeValues != null && !tdfConfig.attributeValues.isEmpty()) {
                 granter = Autoconfigure.newGranterFromAttributes(tdfConfig.attributeValues.toArray(new Value[0]));
             } else if (tdfConfig.attributes != null && !tdfConfig.attributes.isEmpty()) {
-                granter = Autoconfigure.newGranterFromService(attrService, kas.getKeyCache(), tdfConfig.attributes.toArray(new AttributeValueFQN[0]));
+                granter = Autoconfigure.newGranterFromService(attrService, kas.getKeyCache(),
+                        tdfConfig.attributes.toArray(new AttributeValueFQN[0]));
             }
-        
+
             if (granter == null) {
                 throw new AutoConfigureException("Failed to create Granter"); // Replace with appropriate error handling
             }
-        
+
             List<String> dk = defaultKases(tdfConfig);
             tdfConfig.splitPlan = granter.plan(dk, () -> UUID.randomUUID().toString());
-        
+
             if (tdfConfig.splitPlan == null) {
-                throw new AutoConfigureException("Failed to generate Split Plan"); // Replace with appropriate error handling
+                throw new AutoConfigureException("Failed to generate Split Plan"); // Replace with appropriate error
+                                                                                   // handling
             }
         }
 
-        if (tdfConfig.kasInfoList.isEmpty() && (tdfConfig.splitPlan==null || tdfConfig.splitPlan.isEmpty())) {
+        if (tdfConfig.kasInfoList.isEmpty() && (tdfConfig.splitPlan == null || tdfConfig.splitPlan.isEmpty())) {
             throw new KasInfoMissing("kas information is missing, no key access template specified or inferred");
         }
 
@@ -426,7 +425,8 @@ public TDFObject createTDF(InputStream payload,
             do {
                 int nRead = 0;
                 int readThisLoop = 0;
-                while (readThisLoop < readBuf.length && (nRead = payload.read(readBuf, readThisLoop, readBuf.length - readThisLoop)) > 0) {
+                while (readThisLoop < readBuf.length
+                        && (nRead = payload.read(readBuf, readThisLoop, readBuf.length - readThisLoop)) > 0) {
                     readThisLoop += nRead;
                 }
                 finished = nRead < 0;
@@ -469,7 +469,7 @@ public TDFObject createTDF(InputStream payload,
 
         tdfObject.manifest.encryptionInformation.integrityInformation.rootSignature = rootSignature;
         tdfObject.manifest.encryptionInformation.integrityInformation.segmentSizeDefault = tdfConfig.defaultSegmentSize;
-        tdfObject.manifest.encryptionInformation.integrityInformation.encryptedSegmentSizeDefault = (int)encryptedSegmentSize;
+        tdfObject.manifest.encryptionInformation.integrityInformation.encryptedSegmentSizeDefault = (int) encryptedSegmentSize;
 
         tdfObject.manifest.encryptionInformation.integrityInformation.segmentHashAlg = kGmacIntegrityAlgorithm;
         if (tdfConfig.segmentIntegrityAlgorithm == Config.IntegrityAlgorithm.HS256) {
@@ -486,8 +486,9 @@ public TDFObject createTDF(InputStream payload,
         tdfObject.manifest.payload.url = TDFWriter.TDF_PAYLOAD_FILE_NAME;
         tdfObject.manifest.payload.isEncrypted = true;
 
-        List<Manifest.Assertion> signedAssertions = new ArrayList<>();;
-        for (var assertionConfig: tdfConfig.assertionConfigList) {
+        List<Manifest.Assertion> signedAssertions = new ArrayList<>();
+        ;
+        for (var assertionConfig : tdfConfig.assertionConfigList) {
             var assertion = new Manifest.Assertion();
             assertion.id = assertionConfig.id;
             assertion.type = assertionConfig.type.toString();
@@ -538,7 +539,7 @@ public List<String> defaultKases(TDFConfig config) {
     }
 
     private void fillInPublicKeyInfo(List<Config.KASInfo> kasInfoList, SDK.KAS kas) {
-        for (var kasInfo: kasInfoList) {
+        for (var kasInfo : kasInfoList) {
             if (kasInfo.PublicKey != null && !kasInfo.PublicKey.isBlank()) {
                 continue;
             }
@@ -549,7 +550,9 @@ private void fillInPublicKeyInfo(List<Config.KASInfo> kasInfoList, SDK.KAS kas)
         }
     }
 
-    public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVerificationKeys... assertionVerificationKeys) throws NotValidateRootSignature, SegmentSizeMismatch,
+    public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas,
+            Config.AssertionVerificationKeys... assertionVerificationKeys)
+            throws NotValidateRootSignature, SegmentSizeMismatch,
             IOException, FailedToCreateGMAC, JOSEException, ParseException, NoSuchAlgorithmException, DecoderException {
 
         TDFReader tdfReader = new TDFReader(tdf);
@@ -557,25 +560,26 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
         Manifest manifest = gson.fromJson(manifestJson, Manifest.class);
         byte[] payloadKey = new byte[GCM_KEY_SIZE];
         String unencryptedMetadata = null;
-        
+
         Set<String> knownSplits = new HashSet<String>();
-        Set<String> foundSplits = new HashSet<String>();;
+        Set<String> foundSplits = new HashSet<String>();
+        ;
         Map<Autoconfigure.KeySplitStep, Exception> skippedSplits = new HashMap<>();
         boolean mixedSplits = manifest.encryptionInformation.keyAccessObj.size() > 1 &&
-         (manifest.encryptionInformation.keyAccessObj.get(0).sid != null) &&
-          !manifest.encryptionInformation.keyAccessObj.get(0).sid.isEmpty();
+                (manifest.encryptionInformation.keyAccessObj.get(0).sid != null) &&
+                !manifest.encryptionInformation.keyAccessObj.get(0).sid.isEmpty();
 
-        MessageDigest digest =  MessageDigest.getInstance("SHA-256");
+        MessageDigest digest = MessageDigest.getInstance("SHA-256");
 
         if (manifest.payload.isEncrypted) {
-            for (Manifest.KeyAccess keyAccess: manifest.encryptionInformation.keyAccessObj) {
+            for (Manifest.KeyAccess keyAccess : manifest.encryptionInformation.keyAccessObj) {
                 Autoconfigure.KeySplitStep ss = new Autoconfigure.KeySplitStep(keyAccess.url, keyAccess.sid);
                 byte[] unwrappedKey;
                 if (!mixedSplits) {
                     unwrappedKey = kas.unwrap(keyAccess, manifest.encryptionInformation.policy);
                 } else {
                     knownSplits.add(unencryptedMetadata);
-                    if (foundSplits.contains(ss.splitID)){
+                    if (foundSplits.contains(ss.splitID)) {
                         continue;
                     }
                     try {
@@ -585,7 +589,7 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
                         continue;
                     }
                 }
-                
+
                 for (int index = 0; index < unwrappedKey.length; index++) {
                     payloadKey[index] ^= unwrappedKey[index];
                 }
@@ -594,16 +598,18 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
                 if (keyAccess.encryptedMetadata != null && !keyAccess.encryptedMetadata.isEmpty()) {
                     AesGcm aesGcm = new AesGcm(unwrappedKey);
 
-                    String decodedMetadata = new String(Base64.getDecoder().decode(keyAccess.encryptedMetadata), "UTF-8");
+                    String decodedMetadata = new String(Base64.getDecoder().decode(keyAccess.encryptedMetadata),
+                            "UTF-8");
                     EncryptedMetadata encryptedMetadata = gson.fromJson(decodedMetadata, EncryptedMetadata.class);
 
                     var encryptedData = new AesGcm.Encrypted(
-                            decoder.decode(encryptedMetadata.ciphertext)
-                    );
+                            decoder.decode(encryptedMetadata.ciphertext));
 
                     byte[] decrypted = aesGcm.decrypt(encryptedData);
-                    // this is a little bit weird... the last unencrypted metadata we get from a KAS is the one
-                    // that we return to the user. This is OK because we can't have different metadata per-KAS
+                    // this is a little bit weird... the last unencrypted metadata we get from a KAS
+                    // is the one
+                    // that we return to the user. This is OK because we can't have different
+                    // metadata per-KAS
                     unencryptedMetadata = new String(decrypted, StandardCharsets.UTF_8);
                 }
             }
@@ -611,16 +617,16 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
             if (mixedSplits && knownSplits.size() > foundSplits.size()) {
                 List<Exception> exceptionList = new ArrayList<>(skippedSplits.size() + 1);
                 exceptionList.add(new Exception("splitKey.unable to reconstruct split key: " + skippedSplits));
-                
+
                 for (Map.Entry<Autoconfigure.KeySplitStep, Exception> entry : skippedSplits.entrySet()) {
                     exceptionList.add(entry.getValue());
                 }
-                
+
                 StringBuilder combinedMessage = new StringBuilder();
                 for (Exception e : exceptionList) {
                     combinedMessage.append(e.getMessage()).append("\n");
                 }
-                
+
                 throw new SplitKeyException(combinedMessage.toString());
             }
         }
@@ -630,7 +636,7 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
         String rootSignature = manifest.encryptionInformation.integrityInformation.rootSignature.signature;
 
         ByteArrayOutputStream aggregateHash = new ByteArrayOutputStream();
-        for (Manifest.Segment segment: manifest.encryptionInformation.integrityInformation.segments) {
+        for (Manifest.Segment segment : manifest.encryptionInformation.integrityInformation.segments) {
             if (manifest.payload.isEncrypted) {
                 byte[] decodedHash = Base64.getDecoder().decode(segment.hash);
                 aggregateHash.write(decodedHash);
@@ -649,8 +655,7 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
             var sig = calculateSignature(aggregateHash.toByteArray(), payloadKey, sigAlg);
             rootSigValue = Base64.getEncoder().encodeToString(sig.getBytes(StandardCharsets.UTF_8));
 
-        }
-        else {
+        } else {
             rootSigValue = Base64.getEncoder().encodeToString(digest.digest(aggregateHash.toString().getBytes()));
         }
 
@@ -666,7 +671,7 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.AssertionVeri
         }
 
         // Validate assertions
-        for (var assertion: manifest.assertions) {
+        for (var assertion : manifest.assertions) {
             // Set default to HS256
             var assertionKey = new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.HS256, payloadKey);
             if (assertionVerificationKeys != null && assertionVerificationKeys.length > 0) {
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java
index b74c7beb..c83a8bd9 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java
@@ -1,11 +1,8 @@
 package io.opentdf.platform.sdk;
 
 import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.charset.StandardCharsets;
 import java.util.stream.Collectors;
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/ECKeyPair.java
index 4aaa2b8c..72641e68 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/ECKeyPair.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/ECKeyPair.java
@@ -20,11 +20,9 @@
 import org.bouncycastle.util.io.pem.PemReader;
 import org.bouncycastle.jce.spec.ECPublicKeySpec;
 
-
 import javax.crypto.KeyAgreement;
 import java.io.*;
 import java.security.*;
-import java.security.cert.CertificateException;
 import java.security.spec.*;
 // https://www.bouncycastle.org/latest_releases.html
 
@@ -33,6 +31,7 @@ public class ECKeyPair {
     static {
         Security.addProvider(new BouncyCastleProvider());
     }
+
     public enum ECAlgorithm {
         ECDH,
         ECDSA
@@ -57,6 +56,7 @@ public String toString() {
             return name;
         }
     }
+
     private KeyPair keyPair;
     private String curveName;
 
@@ -68,7 +68,8 @@ public ECKeyPair(String curveName, ECAlgorithm algorithm) {
         KeyPairGenerator generator;
 
         try {
-            // Should this just use the algorithm vs use ECDH only for ECDH and ECDSA for everything else.
+            // Should this just use the algorithm vs use ECDH only for ECDH and ECDSA for
+            // everything else.
             if (algorithm == ECAlgorithm.ECDH) {
                 generator = KeyPairGeneratorSpi.getInstance(ECAlgorithm.ECDH.name(), BOUNCY_CASTLE_PROVIDER);
             } else {
@@ -94,11 +95,11 @@ public ECKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey, String curveNam
     }
 
     public ECPublicKey getPublicKey() {
-        return (ECPublicKey)this.keyPair.getPublic();
+        return (ECPublicKey) this.keyPair.getPublic();
     }
 
     public ECPrivateKey getPrivateKey() {
-        return (ECPrivateKey)this.keyPair.getPrivate();
+        return (ECPrivateKey) this.keyPair.getPrivate();
     }
 
     public static int getECKeySize(String curveName) {
@@ -114,7 +115,7 @@ public static int getECKeySize(String curveName) {
         }
     }
 
-    public String publicKeyInPEMFormat()  {
+    public String publicKeyInPEMFormat() {
         StringWriter writer = new StringWriter();
         PemWriter pemWriter = new PemWriter(writer);
 
@@ -149,11 +150,11 @@ public int keySize() {
     }
 
     public String curveName() {
-        return this.curveName = curveName;
+        return this.curveName;
     }
 
-    public  byte[] compressECPublickey() {
-        return ((ECPublicKey)this.keyPair.getPublic()).getQ().getEncoded(true);
+    public byte[] compressECPublickey() {
+        return ((ECPublicKey) this.keyPair.getPublic()).getQ().getEncoded(true);
     }
 
     public static String getPEMPublicKeyFromX509Cert(String pemInX509Format) {
@@ -165,7 +166,7 @@ public static String getPEMPublicKeyFromX509Cert(String pemInX509Format) {
             JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);
             ECPublicKey publicKey = null;
             try {
-                publicKey = (ECPublicKey)converter.getPublicKey(publicKeyInfo);
+                publicKey = (ECPublicKey) converter.getPublicKey(publicKeyInfo);
             } catch (PEMException e) {
                 throw new RuntimeException(e);
             }
@@ -189,19 +190,19 @@ public static byte[] compressECPublickey(String pemECPubKey) {
             PemReader pemReader = new PemReader(new StringReader(pemECPubKey));
             PemObject pemObject = pemReader.readPemObject();
             PublicKey pubKey = ecKeyFac.generatePublic(new X509EncodedKeySpec(pemObject.getContent()));
-            return ((ECPublicKey)pubKey).getQ().getEncoded(true);
+            return ((ECPublicKey) pubKey).getQ().getEncoded(true);
         } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
         } catch (IOException e) {
             throw new RuntimeException(e);
         } catch (InvalidKeySpecException e) {
             throw new RuntimeException(e);
-        }  catch (NoSuchProviderException e) {
+        } catch (NoSuchProviderException e) {
             throw new RuntimeException(e);
         }
     }
 
-    public static String publicKeyFromECPoint(byte[] ecPoint, String curveName)  {
+    public static String publicKeyFromECPoint(byte[] ecPoint, String curveName) {
         try {
             // Create EC Public key
             ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(curveName);
@@ -244,10 +245,11 @@ public static ECPublicKey publicKeyFromPem(String pemEncoding) {
     public static ECPrivateKey privateKeyFromPem(String pemEncoding) {
         try {
             PEMParser parser = new PEMParser(new StringReader(pemEncoding));
-            PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo)parser.readObject();
+            PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) parser.readObject();
             parser.close();
 
-            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);;
+            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);
+            ;
             return (ECPrivateKey) converter.getPrivateKey(privateKeyInfo);
         } catch (IOException e) {
             throw new RuntimeException(e);
@@ -285,7 +287,7 @@ public static byte[] computeECDSASig(byte[] digest, ECPrivateKey privateKey) {
             throw new RuntimeException(e);
         } catch (NoSuchProviderException e) {
             throw new RuntimeException(e);
-        }  catch (InvalidKeyException e) {
+        } catch (InvalidKeyException e) {
             throw new RuntimeException(e);
         } catch (SignatureException e) {
             throw new RuntimeException(e);
@@ -298,11 +300,11 @@ public static Boolean verifyECDSAig(byte[] digest, byte[] signature, ECPublicKey
             ecdsaVerify.initVerify(publicKey);
             ecdsaVerify.update(digest);
             return ecdsaVerify.verify(signature);
-        }  catch (NoSuchAlgorithmException e) {
+        } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
         } catch (NoSuchProviderException e) {
             throw new RuntimeException(e);
-        }  catch (InvalidKeyException e) {
+        } catch (InvalidKeyException e) {
             throw new RuntimeException(e);
         } catch (SignatureException e) {
             throw new RuntimeException(e);
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/Header.java b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/Header.java
index 324e83e6..9328c7a9 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/Header.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/Header.java
@@ -2,7 +2,6 @@
 
 import io.opentdf.platform.sdk.NanoTDF;
 
-import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 
@@ -35,7 +34,7 @@ public Header(ByteBuffer buffer) {
     }
 
     public byte[] getMagicNumberAndVersion() {
-        return Arrays.copyOf(NanoTDF.MAGIC_NUMBER_AND_VERSION,  NanoTDF.MAGIC_NUMBER_AND_VERSION.length);
+        return Arrays.copyOf(NanoTDF.MAGIC_NUMBER_AND_VERSION, NanoTDF.MAGIC_NUMBER_AND_VERSION.length);
     }
 
     public void setMagicNumberAndVersion(byte[] magicNumberAndVersion) {
@@ -45,7 +44,8 @@ public void setMagicNumberAndVersion(byte[] magicNumberAndVersion) {
         if (!Arrays.equals(magicNumberAndVersion, NanoTDF.MAGIC_NUMBER_AND_VERSION)) {
             throw new IllegalArgumentException("Invalid magic number and version. It must be {0x4C, 0x31, 0x4C}.");
         }
-        System.arraycopy(magicNumberAndVersion, 0, NanoTDF.MAGIC_NUMBER_AND_VERSION, 0, NanoTDF.MAGIC_NUMBER_AND_VERSION.length);
+        System.arraycopy(magicNumberAndVersion, 0, NanoTDF.MAGIC_NUMBER_AND_VERSION, 0,
+                NanoTDF.MAGIC_NUMBER_AND_VERSION.length);
     }
 
     public void setKasLocator(ResourceLocator kasLocator) {
@@ -128,31 +128,4 @@ public int writeIntoBuffer(ByteBuffer buffer) {
 
         return totalBytesWritten;
     }
-
-//    public int writeIntoBuffer(OutputStream stream) {
-//        if (buffer.remaining() < getTotalSize()) {
-//            throw new IllegalArgumentException("Failed to write header - invalid buffer size.");
-//        }
-//
-//        int totalBytesWritten = 0;
-//        buffer.put(NanoTDF.MAGIC_NUMBER_AND_VERSION);
-//        totalBytesWritten += NanoTDF.MAGIC_NUMBER_AND_VERSION.length;
-//
-//        int kasLocatorSize = kasLocator.writeIntoBuffer(buffer);
-//        totalBytesWritten += kasLocatorSize;
-//
-//        buffer.put(eccMode.getECCModeAsByte());
-//        totalBytesWritten += 1;
-//
-//        buffer.put(payloadConfig.getSymmetricAndPayloadConfigAsByte());
-//        totalBytesWritten += 1;
-//
-//        int policyInfoSize = policyInfo.writeIntoBuffer(buffer);
-//        totalBytesWritten += policyInfoSize;
-//
-//        buffer.put(ephemeralKey);
-//        totalBytesWritten += ephemeralKey.length;
-//
-//        return totalBytesWritten;
-//    }
 }
\ No newline at end of file
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/PolicyInfo.java b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/PolicyInfo.java
index 799c80a6..c4b93f34 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/PolicyInfo.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/nanotdf/PolicyInfo.java
@@ -1,9 +1,6 @@
 package io.opentdf.platform.sdk.nanotdf;
 
-import io.opentdf.platform.sdk.NanoTDF;
-
 import java.nio.ByteBuffer;
-import java.util.Arrays;
 
 public class PolicyInfo {
     private NanoTDFType.PolicyType type;
@@ -14,7 +11,7 @@ public class PolicyInfo {
     public PolicyInfo() {
     }
 
-    public PolicyInfo(ByteBuffer buffer, ECCMode eccMode)  {
+    public PolicyInfo(ByteBuffer buffer, ECCMode eccMode) {
         this.type = NanoTDFType.PolicyType.values()[buffer.get()];
         this.hasECDSABinding = eccMode.isECDSABindingEnabled();
 
@@ -48,7 +45,7 @@ public PolicyInfo(ByteBuffer buffer, ECCMode eccMode)  {
         }
 
         int bindingBytesSize = 8; // GMAC length
-        if(this.hasECDSABinding) { // ECDSA - The size of binding depends on the curve.
+        if (this.hasECDSABinding) { // ECDSA - The size of binding depends on the curve.
             bindingBytesSize = ECCMode.getECDSASignatureStructSize(eccMode.getEllipticCurveType());
         }
 
@@ -66,7 +63,7 @@ public int getTotalSize() {
             if (type == NanoTDFType.PolicyType.EMBEDDED_POLICY_PLAIN_TEXT ||
                     type == NanoTDFType.PolicyType.EMBEDDED_POLICY_ENCRYPTED) {
 
-                int policySize =  body.length;
+                int policySize = body.length;
                 totalSize = (1 + Short.BYTES + body.length + binding.length);
             } else {
                 throw new RuntimeException("Embedded policy with key access is not supported.");
@@ -101,13 +98,12 @@ public int writeIntoBuffer(ByteBuffer buffer) {
             // 1 - Length of the policy;
             // 2 - policy bytes itself
             // 3 - policy key access( ONLY for EMBEDDED_POLICY_ENCRYPTED_POLICY_KEY_ACCESS)
-            //      1 - resource locator
-            //      2 - ephemeral public key, the size depends on ECC mode.
+            // 1 - resource locator
+            // 2 - ephemeral public key, the size depends on ECC mode.
 
             // Write the length of the policy
 
-
-            short policyLength = (short)body.length;
+            short policyLength = (short) body.length;
             buffer.putShort(policyLength);
             totalBytesWritten += Short.BYTES;
 
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java
index 49e954a0..9446732f 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/AsymEncryptionTest.java
@@ -2,11 +2,6 @@
 
 import static org.junit.jupiter.api.Assertions.*;
 
-import javax.crypto.Cipher;
-import java.security.KeyFactory;
-import java.security.PublicKey;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.Base64;
 import org.junit.jupiter.api.Test;
 
 class AsymEncryptionTest {
@@ -21,7 +16,8 @@ void encryptionWithValidPublicKey() throws Exception {
                 "GBKh0CWGAXWRmphzGj7kFpkAxT1b827MrQMYxkn4w2WB8B/bGKz0+dWyqnnzGYAS\n" +
                 "hVJ0rIiNE8dDWzQCRBfivLemXhX8UFICyoS5i0IwenFvTr6T85EvMxK3aSAlGya3\n" +
                 "3wIDAQAB\n" +
-                "-----END PUBLIC KEY-----";;
+                "-----END PUBLIC KEY-----";
+        ;
         AsymEncryption asymEncryption = new AsymEncryption(publicKeyInPem);
         byte[] plaintext = "Virtru, JavaSDK!".getBytes();
 
@@ -49,7 +45,8 @@ void encryptionWithValidCert() throws Exception {
                 "OcL/UAwQ2pXmfEFjYBs5mDEpKwGC0DxW4tg0FIsb3bbAvqy8ETklExkOh0VfJP4a\n" +
                 "CMz9WjmCfS15t0mPzofK8ir20kF0u0sWvviVVlun+8KYdFOG/wzS100cPNn/wqug\n" +
                 "4w==\n" +
-                "-----END CERTIFICATE-----";;
+                "-----END CERTIFICATE-----";
+        ;
         AsymEncryption asymEncryption = new AsymEncryption(certInPem);
         byte[] plaintext = "Virtru, JavaSDK!".getBytes();
 
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/AutoconfigureTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/AutoconfigureTest.java
index 7f761ac5..0cc7babe 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/AutoconfigureTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/AutoconfigureTest.java
@@ -88,7 +88,6 @@ public static void setup() throws AutoConfigureException {
         UNSPECKED = new Autoconfigure.AttributeNameFQN("https://other.com/attr/unspecified");
         SPECKED = new Autoconfigure.AttributeNameFQN("https://other.com/attr/specified");
 
-
         clsA = new Autoconfigure.AttributeValueFQN("https://virtru.com/attr/Classification/value/Allowed");
         clsS = new Autoconfigure.AttributeValueFQN("https://virtru.com/attr/Classification/value/Secret");
         clsTS = new Autoconfigure.AttributeValueFQN("https://virtru.com/attr/Classification/value/Top%20Secret");
@@ -146,7 +145,7 @@ private static String spongeCase(String s) {
 
     private List<Value> valuesToPolicy(AttributeValueFQN... p) throws AutoConfigureException {
         List<Value> values = new ArrayList<>();
-        for (AttributeValueFQN afqn : List.of(p)){
+        for (AttributeValueFQN afqn : List.of(p)) {
             values.add(mockValueFor(afqn));
         }
         return values;
@@ -154,8 +153,8 @@ private List<Value> valuesToPolicy(AttributeValueFQN... p) throws AutoConfigureE
 
     private List<String> policyToStringKeys(List<AttributeValueFQN> policy) {
         return policy.stream()
-            .map(AttributeValueFQN::getKey)
-            .collect(Collectors.toList());
+                .map(AttributeValueFQN::getKey)
+                .collect(Collectors.toList());
     }
 
     private Autoconfigure.AttributeValueFQN messUpV(Autoconfigure.AttributeValueFQN a) {
@@ -170,29 +169,29 @@ private Attribute mockAttributeFor(Autoconfigure.AttributeNameFQN fqn) {
         Namespace ns1 = Namespace.newBuilder().setId("v").setName("virtru.com").setFqn("https://virtru.com").build();
         Namespace ns2 = Namespace.newBuilder().setId("o").setName("other.com").setFqn("https://other.com").build();
         String key = fqn.getKey();
-        if (key.equals(CLS.getKey())){
-                return Attribute.newBuilder().setId("CLS").setNamespace(ns1)
-                    .setName("Classification").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY).setFqn(fqn.toString()).build();
-        }
-        else if (key.equals(N2K.getKey())) {
+        if (key.equals(CLS.getKey())) {
+            return Attribute.newBuilder().setId("CLS").setNamespace(ns1)
+                    .setName("Classification").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_HIERARCHY)
+                    .setFqn(fqn.toString()).build();
+        } else if (key.equals(N2K.getKey())) {
             return Attribute.newBuilder().setId("N2K").setNamespace(ns1)
-                    .setName("Need to Know").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF).setFqn(fqn.toString()).build();
-        }
-        else if (key.equals(REL.getKey())) {
+                    .setName("Need to Know").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF)
+                    .setFqn(fqn.toString()).build();
+        } else if (key.equals(REL.getKey())) {
             return Attribute.newBuilder().setId("REL").setNamespace(ns1)
-                    .setName("Releasable To").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF).setFqn(fqn.toString()).build();
-        }
-        else if (key.equals(SPECKED.getKey())) {
+                    .setName("Releasable To").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
+                    .setFqn(fqn.toString()).build();
+        } else if (key.equals(SPECKED.getKey())) {
             return Attribute.newBuilder().setId("SPK").setNamespace(ns2)
-                    .setName("specified").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF).setFqn(fqn.toString())
+                    .setName("specified").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
+                    .setFqn(fqn.toString())
                     .addGrants(KeyAccessServer.newBuilder().setUri(SPECIFIED_KAS).build())
                     .build();
-        }
-        else if (key.equals(UNSPECKED.getKey())) {
+        } else if (key.equals(UNSPECKED.getKey())) {
             return Attribute.newBuilder().setId("UNS").setNamespace(ns2)
-                    .setName("unspecified").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF).setFqn(fqn.toString()).build();
-        }
-        else {
+                    .setName("unspecified").setRule(AttributeRuleTypeEnum.ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF)
+                    .setFqn(fqn.toString()).build();
+        } else {
             return null;
         }
     }
@@ -202,13 +201,13 @@ private Value mockValueFor(Autoconfigure.AttributeValueFQN fqn) throws AutoConfi
         Attribute a = mockAttributeFor(an);
         String v = fqn.value();
         Value p = Value.newBuilder()
-        .setId(a.getId() + ":" + v)
-        .setAttribute(a)
-        .setValue(v)
-        .setFqn(fqn.toString())
-        .build();
+                .setId(a.getId() + ":" + v)
+                .setAttribute(a)
+                .setValue(v)
+                .setFqn(fqn.toString())
+                .build();
 
-        if (an.getKey().equals(N2K.getKey())){
+        if (an.getKey().equals(N2K.getKey())) {
             switch (v.toUpperCase()) {
                 case "INT":
                     p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_UK).build()).build();
@@ -220,50 +219,46 @@ private Value mockValueFor(Autoconfigure.AttributeValueFQN fqn) throws AutoConfi
                     p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_US_SA).build()).build();
                     break;
             }
-        }
-        else if (an.getKey().equals(REL.getKey())) {
-                switch (v.toUpperCase()) {
-                    case "FVEY":
-                        p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_AU).build())
-                        .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_CA).build())
-                        .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_UK).build())
-                        .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_NZ).build())
-                        .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_US).build())
-                        .build();
-                        break;
-                    case "AUS":
-                        p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_AU).build())
-                        .build();
-                        break;
-                    case "CAN":
-                        p = p.toBuilder().addGrants(0, KeyAccessServer.newBuilder().setUri(KAS_CA).build())
-                        .build();
-                        break;
-                    case "GBR":
-                        p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_UK).build())
-                        .build();
-                        break;
-                    case "NZL":
-                        p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_NZ).build())
-                        .build();
-                        break;
-                    case "USA":
-                        p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_US).build())
-                        .build();
-                        break;
-                }
-        }
-        else if (an.getKey().equals(CLS.getKey())){
+        } else if (an.getKey().equals(REL.getKey())) {
+            switch (v.toUpperCase()) {
+                case "FVEY":
+                    p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_AU).build())
+                            .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_CA).build())
+                            .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_UK).build())
+                            .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_NZ).build())
+                            .addGrants(1, KeyAccessServer.newBuilder().setUri(KAS_US).build())
+                            .build();
+                    break;
+                case "AUS":
+                    p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_AU).build())
+                            .build();
+                    break;
+                case "CAN":
+                    p = p.toBuilder().addGrants(0, KeyAccessServer.newBuilder().setUri(KAS_CA).build())
+                            .build();
+                    break;
+                case "GBR":
+                    p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_UK).build())
+                            .build();
+                    break;
+                case "NZL":
+                    p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_NZ).build())
+                            .build();
+                    break;
+                case "USA":
+                    p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(KAS_US).build())
+                            .build();
+                    break;
+            }
+        } else if (an.getKey().equals(CLS.getKey())) {
             // defaults only
-        }
-        else if (an.getKey().equals(SPECKED.getKey())){
-            if (fqn.value().toLowerCase().equals("specked")){
+        } else if (an.getKey().equals(SPECKED.getKey())) {
+            if (fqn.value().toLowerCase().equals("specked")) {
                 p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(EVEN_MORE_SPECIFIC_KAS).build())
                         .build();
             }
-        }
-        else if (an.getKey().equals(UNSPECKED.getKey())){
-            if (fqn.value().toLowerCase().equals("specked")){
+        } else if (an.getKey().equals(UNSPECKED.getKey())) {
+            if (fqn.value().toLowerCase().equals("specked")) {
                 p = p.toBuilder().addGrants(KeyAccessServer.newBuilder().setUri(EVEN_MORE_SPECIFIC_KAS).build())
                         .build();
             }
@@ -274,11 +269,10 @@ else if (an.getKey().equals(UNSPECKED.getKey())){
     @Test
     public void testAttributeFromURL() throws AutoConfigureException {
         for (TestCase tc : List.of(
-            new TestCase("letter", "https://e/attr/a", "https://e", "a"),
-            new TestCase("number", "https://e/attr/1", "https://e", "1"),
-            new TestCase("emoji", "https://e/attr/%F0%9F%98%81", "https://e", "😁"),
-            new TestCase("dash", "https://a-b.com/attr/b-c", "https://a-b.com", "b-c")
-        )) {
+                new TestCase("letter", "https://e/attr/a", "https://e", "a"),
+                new TestCase("number", "https://e/attr/1", "https://e", "1"),
+                new TestCase("emoji", "https://e/attr/%F0%9F%98%81", "https://e", "😁"),
+                new TestCase("dash", "https://a-b.com/attr/b-c", "https://a-b.com", "b-c"))) {
             Autoconfigure.AttributeNameFQN a = new Autoconfigure.AttributeNameFQN(tc.getU());
             assertThat(a.authority()).isEqualTo(tc.getAuth());
             assertThat(a.name()).isEqualTo(tc.getName());
@@ -288,29 +282,27 @@ public void testAttributeFromURL() throws AutoConfigureException {
     @Test
     public void testAttributeFromMalformedURL() {
         for (TestCase tc : List.of(
-            new TestCase("no name", "https://e/attr"),
-            new TestCase("invalid prefix 1", "hxxp://e/attr/a"),
-            new TestCase("invalid prefix 2", "e/attr/a"),
-            new TestCase("invalid prefix 3", "file://e/attr/a"),
-            new TestCase("invalid prefix 4", "https:///attr/a"),
-            new TestCase("bad encoding", "https://a/attr/%😁"),
-            new TestCase("with value", "https://e/attr/a/value/b")
-        )) {
+                new TestCase("no name", "https://e/attr"),
+                new TestCase("invalid prefix 1", "hxxp://e/attr/a"),
+                new TestCase("invalid prefix 2", "e/attr/a"),
+                new TestCase("invalid prefix 3", "file://e/attr/a"),
+                new TestCase("invalid prefix 4", "https:///attr/a"),
+                new TestCase("bad encoding", "https://a/attr/%😁"),
+                new TestCase("with value", "https://e/attr/a/value/b"))) {
             assertThatThrownBy(() -> new Autoconfigure.AttributeNameFQN(tc.getU()))
-                .isInstanceOf(AutoConfigureException.class);
+                    .isInstanceOf(AutoConfigureException.class);
         }
     }
 
     @Test
     public void testAttributeValueFromURL() {
         List<TestCase> testCases = List.of(
-            new TestCase("number", "https://e/attr/a/value/1", "https://e", "a", "1"),
-            new TestCase("space", "https://e/attr/a/value/%20", "https://e", "a", " "),
-            new TestCase("emoji", "https://e/attr/a/value/%F0%9F%98%81", "https://e", "a", "😁"),
-            new TestCase("numberdef", "https://e/attr/1/value/one", "https://e", "1", "one"),
-            new TestCase("valuevalue", "https://e/attr/value/value/one", "https://e", "value", "one"),
-            new TestCase("dash", "https://a-b.com/attr/b-c/value/c-d", "https://a-b.com", "b-c", "c-d")
-        );
+                new TestCase("number", "https://e/attr/a/value/1", "https://e", "a", "1"),
+                new TestCase("space", "https://e/attr/a/value/%20", "https://e", "a", " "),
+                new TestCase("emoji", "https://e/attr/a/value/%F0%9F%98%81", "https://e", "a", "😁"),
+                new TestCase("numberdef", "https://e/attr/1/value/one", "https://e", "1", "one"),
+                new TestCase("valuevalue", "https://e/attr/value/value/one", "https://e", "value", "one"),
+                new TestCase("dash", "https://a-b.com/attr/b-c/value/c-d", "https://a-b.com", "b-c", "c-d"));
 
         for (TestCase tc : testCases) {
             assertDoesNotThrow(() -> {
@@ -325,29 +317,28 @@ public void testAttributeValueFromURL() {
     @Test
     public void testAttributeValueFromMalformedURL() {
         List<TestCase> testCases = List.of(
-            new TestCase("no name", "https://e/attr/value/1"),
-            new TestCase("no value", "https://e/attr/who/value"),
-            new TestCase("invalid prefix 1", "hxxp://e/attr/a/value/1"),
-            new TestCase("invalid prefix 2", "e/attr/a/a/value/1"),
-            new TestCase("bad encoding", "https://a/attr/emoji/value/%😁")
-        );
+                new TestCase("no name", "https://e/attr/value/1"),
+                new TestCase("no value", "https://e/attr/who/value"),
+                new TestCase("invalid prefix 1", "hxxp://e/attr/a/value/1"),
+                new TestCase("invalid prefix 2", "e/attr/a/a/value/1"),
+                new TestCase("bad encoding", "https://a/attr/emoji/value/%😁"));
 
         for (TestCase tc : testCases) {
             assertThatThrownBy(() -> new AttributeValueFQN(tc.getU()))
-                .isInstanceOf(AutoConfigureException.class)
-                .hasMessageContaining("invalid type");
+                    .isInstanceOf(AutoConfigureException.class)
+                    .hasMessageContaining("invalid type");
         }
     }
 
     @Test
     public void testConfigurationServicePutGet() {
         List<ConfigurationTestCase> testCases = List.of(
-            new ConfigurationTestCase("default", List.of(clsA), 1, List.of()),
-            new ConfigurationTestCase("one-country", List.of(rel2gbr), 1, List.of(KAS_UK)),
-            new ConfigurationTestCase("two-country", List.of(rel2gbr, rel2nzl), 2, List.of(KAS_UK, KAS_NZ)),
-            new ConfigurationTestCase("with-default", List.of(clsA, rel2gbr), 2, List.of(KAS_UK)),
-            new ConfigurationTestCase("need-to-know", List.of(clsTS, rel2usa, n2kSI), 3, List.of(KAS_US, KAS_US_SA))
-        );
+                new ConfigurationTestCase("default", List.of(clsA), 1, List.of()),
+                new ConfigurationTestCase("one-country", List.of(rel2gbr), 1, List.of(KAS_UK)),
+                new ConfigurationTestCase("two-country", List.of(rel2gbr, rel2nzl), 2, List.of(KAS_UK, KAS_NZ)),
+                new ConfigurationTestCase("with-default", List.of(clsA, rel2gbr), 2, List.of(KAS_UK)),
+                new ConfigurationTestCase("need-to-know", List.of(clsTS, rel2usa, n2kSI), 3,
+                        List.of(KAS_US, KAS_US_SA)));
 
         for (ConfigurationTestCase tc : testCases) {
             assertDoesNotThrow(() -> {
@@ -359,91 +350,85 @@ public void testConfigurationServicePutGet() {
                 Set<String> actualKases = new HashSet<>();
                 for (Autoconfigure.KeyAccessGrant g : grants.getGrants().values()) {
                     assertThat(g).isNotNull();
-                    for (String k : g.kases){
+                    for (String k : g.kases) {
                         actualKases.add(k);
                     }
                 }
 
                 String[] kasArray = tc.getKases().toArray(new String[tc.getKases().size()]);
                 assertThat(actualKases).containsExactlyInAnyOrder(kasArray);
-            }
-            );
+            });
         }
     }
 
     @Test
     public void testReasonerConstructAttributeBoolean() {
         List<ReasonerTestCase> testCases = List.of(
-            new ReasonerTestCase(
-                "one actual with default",
-                List.of(clsS, rel2can),
-                List.of(KAS_US),
-                "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/CAN",
-                "[DEFAULT]&(https://kas.ca/)",
-                "(https://kas.ca/)",
-                List.of(new KeySplitStep(KAS_CA, ""))
-            ),
-            new ReasonerTestCase(
-                "one defaulted attr",
-                List.of(clsS),
-                List.of(KAS_US),
-                "https://virtru.com/attr/Classification/value/Secret",
-                "[DEFAULT]",
-                "",
-                List.of(new KeySplitStep(KAS_US, ""))
-            ),
-            new ReasonerTestCase(
-                "empty policy",
-                List.of(),
-                List.of(KAS_US),
-                "∅",
-                "",
-                "",
-                List.of(new KeySplitStep(KAS_US, ""))
-            ),
-            new ReasonerTestCase(
-                "old school splits",
-                List.of(),
-                List.of(KAS_AU, KAS_CA, KAS_US),
-                "∅",
-                "",
-                "",
-                List.of(new KeySplitStep(KAS_AU, "1"), new KeySplitStep(KAS_CA, "2"), new KeySplitStep(KAS_US, "3"))
-            ),
-            new ReasonerTestCase(
-                "simple with all three ops",
-                List.of(clsS, rel2gbr, n2kInt),
-                List.of(KAS_US),
-                "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/GBR&https://virtru.com/attr/Need%20to%20Know/value/INT",
-                "[DEFAULT]&(https://kas.uk/)&(https://kas.uk/)",
-                "(https://kas.uk/)",
-                List.of(new KeySplitStep(KAS_UK, ""))
-            ),
-            new ReasonerTestCase(
-                "compartments",
-                List.of(clsS, rel2gbr, rel2usa, n2kHCS, n2kSI),
-                List.of(KAS_US),
-                "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
-                "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
-                "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
-                List.of(new KeySplitStep(KAS_UK, "1"), new KeySplitStep(KAS_US, "1"), new KeySplitStep(KAS_US_HCS, "2"), new KeySplitStep(KAS_US_SA, "3"))
-            ),
-            new ReasonerTestCase(
-                "compartments - case insensitive",
-                List.of(
-                    messUpV(clsS), messUpV(rel2gbr), messUpV(rel2usa), messUpV(n2kHCS), messUpV(n2kSI)
-                ),
-                List.of(KAS_US),
-                "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
-                "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
-                "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
-                List.of(new KeySplitStep(KAS_UK, "1"), new KeySplitStep(KAS_US, "1"), new KeySplitStep(KAS_US_HCS, "2"), new KeySplitStep(KAS_US_SA, "3"))
-            )
-        );
+                new ReasonerTestCase(
+                        "one actual with default",
+                        List.of(clsS, rel2can),
+                        List.of(KAS_US),
+                        "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/CAN",
+                        "[DEFAULT]&(https://kas.ca/)",
+                        "(https://kas.ca/)",
+                        List.of(new KeySplitStep(KAS_CA, ""))),
+                new ReasonerTestCase(
+                        "one defaulted attr",
+                        List.of(clsS),
+                        List.of(KAS_US),
+                        "https://virtru.com/attr/Classification/value/Secret",
+                        "[DEFAULT]",
+                        "",
+                        List.of(new KeySplitStep(KAS_US, ""))),
+                new ReasonerTestCase(
+                        "empty policy",
+                        List.of(),
+                        List.of(KAS_US),
+                        "∅",
+                        "",
+                        "",
+                        List.of(new KeySplitStep(KAS_US, ""))),
+                new ReasonerTestCase(
+                        "old school splits",
+                        List.of(),
+                        List.of(KAS_AU, KAS_CA, KAS_US),
+                        "∅",
+                        "",
+                        "",
+                        List.of(new KeySplitStep(KAS_AU, "1"), new KeySplitStep(KAS_CA, "2"),
+                                new KeySplitStep(KAS_US, "3"))),
+                new ReasonerTestCase(
+                        "simple with all three ops",
+                        List.of(clsS, rel2gbr, n2kInt),
+                        List.of(KAS_US),
+                        "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/GBR&https://virtru.com/attr/Need%20to%20Know/value/INT",
+                        "[DEFAULT]&(https://kas.uk/)&(https://kas.uk/)",
+                        "(https://kas.uk/)",
+                        List.of(new KeySplitStep(KAS_UK, ""))),
+                new ReasonerTestCase(
+                        "compartments",
+                        List.of(clsS, rel2gbr, rel2usa, n2kHCS, n2kSI),
+                        List.of(KAS_US),
+                        "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
+                        "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
+                        "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
+                        List.of(new KeySplitStep(KAS_UK, "1"), new KeySplitStep(KAS_US, "1"),
+                                new KeySplitStep(KAS_US_HCS, "2"), new KeySplitStep(KAS_US_SA, "3"))),
+                new ReasonerTestCase(
+                        "compartments - case insensitive",
+                        List.of(
+                                messUpV(clsS), messUpV(rel2gbr), messUpV(rel2usa), messUpV(n2kHCS), messUpV(n2kSI)),
+                        List.of(KAS_US),
+                        "https://virtru.com/attr/Classification/value/Secret&https://virtru.com/attr/Releasable%20To/value/{GBR,USA}&https://virtru.com/attr/Need%20to%20Know/value/{HCS,SI}",
+                        "[DEFAULT]&(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/⋀https://si.kas.us/)",
+                        "(https://kas.uk/⋁https://kas.us/)&(https://hcs.kas.us/)&(https://si.kas.us/)",
+                        List.of(new KeySplitStep(KAS_UK, "1"), new KeySplitStep(KAS_US, "1"),
+                                new KeySplitStep(KAS_US_HCS, "2"), new KeySplitStep(KAS_US_SA, "3"))));
 
         for (ReasonerTestCase tc : testCases) {
             assertDoesNotThrow(() -> {
-                Granter reasoner = Autoconfigure.newGranterFromAttributes(valuesToPolicy(tc.getPolicy().toArray(new AttributeValueFQN[0])).toArray(new Value[0]));
+                Granter reasoner = Autoconfigure.newGranterFromAttributes(
+                        valuesToPolicy(tc.getPolicy().toArray(new AttributeValueFQN[0])).toArray(new Value[0]));
                 assertThat(reasoner).isNotNull();
 
                 AttributeBooleanExpression actualAB = reasoner.constructAttributeBoolean();
@@ -455,16 +440,17 @@ public void testReasonerConstructAttributeBoolean() {
                 String reduced = actualKeyed.reduce().toString();
                 assertThat(reduced).isEqualTo(tc.getReduced());
 
-                var wrapper = new Object(){ int i = 0; };
+                var wrapper = new Object() {
+                    int i = 0;
+                };
                 List<KeySplitStep> plan = reasoner.plan(tc.getDefaults(), () -> {
                     return String.valueOf(wrapper.i++ + 1);
                 }
-                
+
                 );
                 assertThat(plan.size()).isEqualTo(tc.getPlan().size());
                 assertThat(plan).isEqualTo(tc.getPlan());
-            }
-            );
+            });
         }
     }
 
@@ -476,15 +462,15 @@ GetAttributeValuesByFqnsResponse getResponse(GetAttributeValuesByFqnsRequest req
             try {
                 vfqn = new AttributeValueFQN(v);
             } catch (Exception e) {
-                return null;  // Or throw the exception as needed
+                return null; // Or throw the exception as needed
             }
 
             Value val = mockValueFor(vfqn);
-            
+
             builder.putFqnAttributeValues(v, GetAttributeValuesByFqnsResponse.AttributeAndValue.newBuilder()
-            .setAttribute(val.getAttribute())
-            .setValue(val)
-            .build());
+                    .setAttribute(val.getAttribute())
+                    .setValue(val)
+                    .build());
         }
 
         return builder.build();
@@ -493,96 +479,89 @@ GetAttributeValuesByFqnsResponse getResponse(GetAttributeValuesByFqnsRequest req
     @Test
     public void testReasonerSpecificity() {
         List<ReasonerTestCase> testCases = List.of(
-            new ReasonerTestCase(
-                "uns.uns => default",
-                List.of(uns2uns),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(KAS_US, ""))
-            ),
-            new ReasonerTestCase(
-                "uns.spk => spk",
-                List.of(uns2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "spk.uns => spk",
-                List.of(spk2uns),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(SPECIFIED_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "spk.spk => value.spk",
-                List.of(spk2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "spk.spk & spk.uns => value.spk || attr.spk",
-                List.of(spk2spk, spk2uns),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, "1"), new KeySplitStep(SPECIFIED_KAS, "1"))
-            ),
-            new ReasonerTestCase(
-                "spk.uns & spk.spk => value.spk || attr.spk",
-                List.of(spk2uns, spk2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(SPECIFIED_KAS, "1"), new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, "1"))
-            ),
-            new ReasonerTestCase(
-                "uns.spk & spk.spk => value.spk",
-                List.of(spk2spk, uns2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "uns.spk & uns.uns => spk",
-                List.of(uns2spk, uns2uns),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "uns.uns & uns.spk => spk",
-                List.of(uns2uns, uns2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            ),
-            new ReasonerTestCase(
-                "uns.uns & uns.spk => spk",
-                List.of(uns2uns, spk2spk),
-                List.of(KAS_US),
-                List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))
-            )
-        );
+                new ReasonerTestCase(
+                        "uns.uns => default",
+                        List.of(uns2uns),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(KAS_US, ""))),
+                new ReasonerTestCase(
+                        "uns.spk => spk",
+                        List.of(uns2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))),
+                new ReasonerTestCase(
+                        "spk.uns => spk",
+                        List.of(spk2uns),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(SPECIFIED_KAS, ""))),
+                new ReasonerTestCase(
+                        "spk.spk => value.spk",
+                        List.of(spk2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))),
+                new ReasonerTestCase(
+                        "spk.spk & spk.uns => value.spk || attr.spk",
+                        List.of(spk2spk, spk2uns),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, "1"), new KeySplitStep(SPECIFIED_KAS, "1"))),
+                new ReasonerTestCase(
+                        "spk.uns & spk.spk => value.spk || attr.spk",
+                        List.of(spk2uns, spk2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(SPECIFIED_KAS, "1"), new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, "1"))),
+                new ReasonerTestCase(
+                        "uns.spk & spk.spk => value.spk",
+                        List.of(spk2spk, uns2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))),
+                new ReasonerTestCase(
+                        "uns.spk & uns.uns => spk",
+                        List.of(uns2spk, uns2uns),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))),
+                new ReasonerTestCase(
+                        "uns.uns & uns.spk => spk",
+                        List.of(uns2uns, uns2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))),
+                new ReasonerTestCase(
+                        "uns.uns & uns.spk => spk",
+                        List.of(uns2uns, spk2spk),
+                        List.of(KAS_US),
+                        List.of(new KeySplitStep(EVEN_MORE_SPECIFIC_KAS, ""))));
 
         for (ReasonerTestCase tc : testCases) {
             assertDoesNotThrow(() -> {
-                AttributesServiceGrpc.AttributesServiceFutureStub attributeGrpcStub = mock(AttributesServiceGrpc.AttributesServiceFutureStub.class);
-                lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenAnswer(
-                    invocation -> {
-                        GetAttributeValuesByFqnsResponse resp = getResponse((GetAttributeValuesByFqnsRequest) invocation.getArguments()[0]);
-                        SettableFuture<GetAttributeValuesByFqnsResponse> future = SettableFuture.create();
-                        future.set(resp);  // Set the request as the future's result
-                        return future;
-                });
-
-                Granter reasoner = Autoconfigure.newGranterFromService(attributeGrpcStub, new KASKeyCache(), tc.getPolicy().toArray(new AttributeValueFQN[0]));
+                AttributesServiceGrpc.AttributesServiceFutureStub attributeGrpcStub = mock(
+                        AttributesServiceGrpc.AttributesServiceFutureStub.class);
+                lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                        .thenAnswer(
+                                invocation -> {
+                                    GetAttributeValuesByFqnsResponse resp = getResponse(
+                                            (GetAttributeValuesByFqnsRequest) invocation.getArguments()[0]);
+                                    SettableFuture<GetAttributeValuesByFqnsResponse> future = SettableFuture.create();
+                                    future.set(resp); // Set the request as the future's result
+                                    return future;
+                                });
+
+                Granter reasoner = Autoconfigure.newGranterFromService(attributeGrpcStub, new KASKeyCache(),
+                        tc.getPolicy().toArray(new AttributeValueFQN[0]));
                 assertThat(reasoner).isNotNull();
 
-                var wrapper = new Object(){ int i = 0; };
+                var wrapper = new Object() {
+                    int i = 0;
+                };
                 List<KeySplitStep> plan = reasoner.plan(tc.getDefaults(), () -> {
                     return String.valueOf(wrapper.i++ + 1);
                 }
-                
+
                 );
                 assertThat(plan.size()).isEqualTo(tc.getPlan().size());
                 assertThat(plan).hasSameElementsAs(tc.getPlan());
-            }
-            );
+            });
         }
     }
 
-
     private static class TestCase {
         private final String n;
         private final String u;
@@ -590,7 +569,6 @@ private static class TestCase {
         private final String name;
         private final String value;
 
-
         TestCase(String n, String u, String auth, String name, String value) {
             this.n = n;
             this.u = u;
@@ -667,7 +645,8 @@ private static class ReasonerTestCase {
         private final String reduced;
         private final List<KeySplitStep> plan;
 
-        ReasonerTestCase(String name, List<AttributeValueFQN> policy, List<String> defaults, String ats, String keyed, String reduced, List<KeySplitStep> plan) {
+        ReasonerTestCase(String name, List<AttributeValueFQN> policy, List<String> defaults, String ats, String keyed,
+                String reduced, List<KeySplitStep> plan) {
             this.name = name;
             this.policy = policy;
             this.defaults = defaults;
@@ -720,10 +699,9 @@ public List<KeySplitStep> getPlan() {
     void testStoreKeysToCache_NoKeys() {
         KASKeyCache keyCache = Mockito.mock(KASKeyCache.class);
         KeyAccessServer kas1 = KeyAccessServer.newBuilder().setPublicKey(
-            PublicKey.newBuilder().setCached(
-                KasPublicKeySet.newBuilder())
-                ).build();
-
+                PublicKey.newBuilder().setCached(
+                        KasPublicKeySet.newBuilder()))
+                .build();
 
         List<KeyAccessServer> kases = List.of(kas1);
 
@@ -739,10 +717,10 @@ void testStoreKeysToCache_WithKeys() {
 
         // Create the KasPublicKey object
         KasPublicKey kasPublicKey1 = KasPublicKey.newBuilder()
-            .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
-            .setKid("test-kid")
-            .setPem("public-key-pem")
-            .build();
+                .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
+                .setKid("test-kid")
+                .setPem("public-key-pem")
+                .build();
 
         // Add the KasPublicKey to a list
         List<KasPublicKey> kasPublicKeys = new ArrayList<>();
@@ -750,13 +728,12 @@ void testStoreKeysToCache_WithKeys() {
 
         // Create the KeyAccessServer object
         KeyAccessServer kas1 = KeyAccessServer.newBuilder()
-            .setPublicKey(PublicKey.newBuilder()
-                .setCached(KasPublicKeySet.newBuilder()
-                    .addAllKeys(kasPublicKeys)
-                    .build())
-            )
-            .setUri("https://example.com/kas")
-            .build();
+                .setPublicKey(PublicKey.newBuilder()
+                        .setCached(KasPublicKeySet.newBuilder()
+                                .addAllKeys(kasPublicKeys)
+                                .build()))
+                .setUri("https://example.com/kas")
+                .build();
 
         // Add the KeyAccessServer to a list
         List<KeyAccessServer> kases = List.of(kas1);
@@ -780,15 +757,15 @@ void testStoreKeysToCache_MultipleKasEntries() {
 
         // Create the KasPublicKey object
         KasPublicKey kasPublicKey1 = KasPublicKey.newBuilder()
-            .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
-            .setKid("test-kid")
-            .setPem("public-key-pem")
-            .build();
+                .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
+                .setKid("test-kid")
+                .setPem("public-key-pem")
+                .build();
         KasPublicKey kasPublicKey2 = KasPublicKey.newBuilder()
-            .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048)
-            .setKid("test-kid-2")
-            .setPem("public-key-pem-2")
-            .build();
+                .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048)
+                .setKid("test-kid-2")
+                .setPem("public-key-pem-2")
+                .build();
 
         // Add the KasPublicKey to a list
         List<KasPublicKey> kasPublicKeys = new ArrayList<>();
@@ -797,13 +774,12 @@ void testStoreKeysToCache_MultipleKasEntries() {
 
         // Create the KeyAccessServer object
         KeyAccessServer kas1 = KeyAccessServer.newBuilder()
-            .setPublicKey(PublicKey.newBuilder()
-                .setCached(KasPublicKeySet.newBuilder()
-                    .addAllKeys(kasPublicKeys)
-                    .build())
-            )
-            .setUri("https://example.com/kas")
-            .build();
+                .setPublicKey(PublicKey.newBuilder()
+                        .setCached(KasPublicKeySet.newBuilder()
+                                .addAllKeys(kasPublicKeys)
+                                .build()))
+                .setUri("https://example.com/kas")
+                .build();
 
         // Add the KeyAccessServer to a list
         List<KeyAccessServer> kases = List.of(kas1);
@@ -827,8 +803,8 @@ void testStoreKeysToCache_MultipleKasEntries() {
         assertEquals("public-key-pem-2", storedKASInfo2.PublicKey);
     }
 
-
-    GetAttributeValuesByFqnsResponse getResponseWithGrants(GetAttributeValuesByFqnsRequest req, List<KeyAccessServer> grants) {
+    GetAttributeValuesByFqnsResponse getResponseWithGrants(GetAttributeValuesByFqnsRequest req,
+            List<KeyAccessServer> grants) {
         GetAttributeValuesByFqnsResponse.Builder builder = GetAttributeValuesByFqnsResponse.newBuilder();
 
         for (String v : req.getFqnsList()) {
@@ -836,34 +812,33 @@ GetAttributeValuesByFqnsResponse getResponseWithGrants(GetAttributeValuesByFqnsR
             try {
                 vfqn = new AttributeValueFQN(v);
             } catch (Exception e) {
-                return null;  // Or throw the exception as needed
+                return null; // Or throw the exception as needed
             }
 
             Value val = Value.newBuilder(mockValueFor(vfqn)).addAllGrants(grants).build();
-            
+
             builder.putFqnAttributeValues(v, GetAttributeValuesByFqnsResponse.AttributeAndValue.newBuilder()
-            .setAttribute(val.getAttribute())
-            .setValue(val)
-            .build());
+                    .setAttribute(val.getAttribute())
+                    .setValue(val)
+                    .build());
         }
 
         return builder.build();
     }
 
-
     @Test
     void testKeyCacheFromGrants() throws InterruptedException, ExecutionException {
         // Create the KasPublicKey object
         KasPublicKey kasPublicKey1 = KasPublicKey.newBuilder()
-            .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
-            .setKid("test-kid")
-            .setPem("public-key-pem")
-            .build();
+                .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_EC_SECP256R1)
+                .setKid("test-kid")
+                .setPem("public-key-pem")
+                .build();
         KasPublicKey kasPublicKey2 = KasPublicKey.newBuilder()
-            .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048)
-            .setKid("test-kid-2")
-            .setPem("public-key-pem-2")
-            .build();
+                .setAlg(KasPublicKeyAlgEnum.KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048)
+                .setKid("test-kid-2")
+                .setPem("public-key-pem-2")
+                .build();
 
         // Add the KasPublicKey to a list
         List<KasPublicKey> kasPublicKeys = new ArrayList<>();
@@ -872,26 +847,29 @@ void testKeyCacheFromGrants() throws InterruptedException, ExecutionException {
 
         // Create the KeyAccessServer object
         KeyAccessServer kas1 = KeyAccessServer.newBuilder()
-            .setPublicKey(PublicKey.newBuilder()
-                .setCached(KasPublicKeySet.newBuilder()
-                    .addAllKeys(kasPublicKeys)
-                    .build())
-            )
-            .setUri("https://example.com/kas")
-            .build();
-        
-        AttributesServiceGrpc.AttributesServiceFutureStub attributeGrpcStub = mock(AttributesServiceGrpc.AttributesServiceFutureStub.class);
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenAnswer(
-            invocation -> {
-                GetAttributeValuesByFqnsResponse resp = getResponseWithGrants((GetAttributeValuesByFqnsRequest) invocation.getArguments()[0], List.of(kas1));
-                SettableFuture<GetAttributeValuesByFqnsResponse> future = SettableFuture.create();
-                future.set(resp);  // Set the request as the future's result
-                return future;
-        });
+                .setPublicKey(PublicKey.newBuilder()
+                        .setCached(KasPublicKeySet.newBuilder()
+                                .addAllKeys(kasPublicKeys)
+                                .build()))
+                .setUri("https://example.com/kas")
+                .build();
+
+        AttributesServiceGrpc.AttributesServiceFutureStub attributeGrpcStub = mock(
+                AttributesServiceGrpc.AttributesServiceFutureStub.class);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenAnswer(
+                        invocation -> {
+                            GetAttributeValuesByFqnsResponse resp = getResponseWithGrants(
+                                    (GetAttributeValuesByFqnsRequest) invocation.getArguments()[0], List.of(kas1));
+                            SettableFuture<GetAttributeValuesByFqnsResponse> future = SettableFuture.create();
+                            future.set(resp); // Set the request as the future's result
+                            return future;
+                        });
 
         KASKeyCache keyCache = new KASKeyCache();
 
-        Granter reasoner = Autoconfigure.newGranterFromService(attributeGrpcStub, keyCache, List.of(clsS, rel2gbr, rel2usa, n2kHCS, n2kSI).toArray(new AttributeValueFQN[0]));
+        Granter reasoner = Autoconfigure.newGranterFromService(attributeGrpcStub, keyCache,
+                List.of(clsS, rel2gbr, rel2usa, n2kHCS, n2kSI).toArray(new AttributeValueFQN[0]));
         assertThat(reasoner).isNotNull();
 
         // Verify that the key was stored in the cache
@@ -911,5 +889,4 @@ void testKeyCacheFromGrants() throws InterruptedException, ExecutionException {
 
     }
 
-    
 }
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java
index 8f816548..f44bc564 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java
@@ -57,7 +57,8 @@ public void publicKey(PublicKeyRequest request, StreamObserver<PublicKeyResponse
                     .build();
 
             var keypair = CryptoUtils.generateRSAKeypair();
-            var dpopKey = new RSAKey.Builder((RSAPublicKey) keypair.getPublic()).privateKey(keypair.getPrivate()).build();
+            var dpopKey = new RSAKey.Builder((RSAPublicKey) keypair.getPublic()).privateKey(keypair.getPrivate())
+                    .build();
             try (var kas = new KASClient(channelFactory, dpopKey)) {
                 Config.KASInfo kasInfo = new Config.KASInfo();
                 kasInfo.URL = "localhost:" + rewrapServer.getPort();
@@ -90,7 +91,8 @@ public void publicKey(PublicKeyRequest request, StreamObserver<PublicKeyResponse
                     .build();
 
             var keypair = CryptoUtils.generateRSAKeypair();
-            var dpopKey = new RSAKey.Builder((RSAPublicKey) keypair.getPublic()).privateKey(keypair.getPrivate()).build();
+            var dpopKey = new RSAKey.Builder((RSAPublicKey) keypair.getPublic()).privateKey(keypair.getPrivate())
+                    .build();
             try (var kas = new KASClient(channelFactory, dpopKey)) {
                 Config.KASInfo kasInfo = new Config.KASInfo();
                 kasInfo.URL = "localhost:" + server.getPort();
@@ -106,7 +108,8 @@ public void publicKey(PublicKeyRequest request, StreamObserver<PublicKeyResponse
     @Test
     void testCallingRewrap() throws IOException {
         var dpopKeypair = CryptoUtils.generateRSAKeypair();
-        var dpopKey = new RSAKey.Builder((RSAPublicKey)dpopKeypair.getPublic()).privateKey(dpopKeypair.getPrivate()).build();
+        var dpopKey = new RSAKey.Builder((RSAPublicKey) dpopKeypair.getPublic()).privateKey(dpopKeypair.getPrivate())
+                .build();
         var serverKeypair = CryptoUtils.generateRSAKeypair();
         AccessServiceGrpc.AccessServiceImplBase accessService = new AccessServiceGrpc.AccessServiceImplBase() {
             @Override
@@ -138,10 +141,12 @@ public void rewrap(RewrapRequest request, StreamObserver<RewrapResponse> respons
                 var gson = new Gson();
                 var req = gson.fromJson(requestBodyJson, KASClient.RewrapRequestBody.class);
 
-                var decryptedKey = new AsymDecryption(serverKeypair.getPrivate()).decrypt(Base64.getDecoder().decode(req.keyAccess.wrappedKey));
+                var decryptedKey = new AsymDecryption(serverKeypair.getPrivate())
+                        .decrypt(Base64.getDecoder().decode(req.keyAccess.wrappedKey));
                 var encryptedKey = new AsymEncryption(req.clientPublicKey).encrypt(decryptedKey);
 
-                responseObserver.onNext(RewrapResponse.newBuilder().setEntityWrappedKey(ByteString.copyFrom(encryptedKey)).build());
+                responseObserver.onNext(
+                        RewrapResponse.newBuilder().setEntityWrappedKey(ByteString.copyFrom(encryptedKey)).build());
                 responseObserver.onCompleted();
             }
         };
@@ -174,7 +179,8 @@ public void rewrap(RewrapRequest request, StreamObserver<RewrapResponse> respons
     public void testAddressNormalization() {
         var lastAddress = new AtomicReference<String>();
         var dpopKeypair = CryptoUtils.generateRSAKeypair();
-        var dpopKey = new RSAKey.Builder((RSAPublicKey)dpopKeypair.getPublic()).privateKey(dpopKeypair.getPrivate()).build();
+        var dpopKey = new RSAKey.Builder((RSAPublicKey) dpopKeypair.getPublic()).privateKey(dpopKeypair.getPrivate())
+                .build();
         var kasClient = new KASClient(addr -> {
             lastAddress.set(addr);
             return ManagedChannelBuilder.forTarget(addr).build();
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
index e35c7385..0a85a181 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
@@ -45,10 +45,9 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.*;
 
-
 public class SDKBuilderTest {
 
-    final String EXAMPLE_COM_PEM= "-----BEGIN CERTIFICATE-----\n" +
+    final String EXAMPLE_COM_PEM = "-----BEGIN CERTIFICATE-----\n" +
             "MIIBqTCCARKgAwIBAgIIT0xFd/5uogEwDQYJKoZIhvcNAQEFBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" +
             "ZS5jb20wIBcNMTcwMTIwMTczOTIwWhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" +
             "bGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2Tl2MdaUFmjAaYwmEwgEVRfVqwJO4\n" +
@@ -57,45 +56,46 @@ public class SDKBuilderTest {
             "CSqGSIb3DQEBBQUAA4GBAGfw0xavZSJXxuFAwxCZBtne9BAtk+SmfKkTI21v8Tx6w/p5Yt0IIvF3\n" +
             "0wCES7YVZ+zUc8vtVVyk1q3f1ZqXqVvzRCjzLzQnu6VVLBaiZPH9SYNX6j0pHhBvx1ZUMopJPr2D\n" +
             "avTXCTSHY5JoX20KEwfu8QQXQRDUzyc0QKn9SiE3\n" +
-    "-----END CERTIFICATE-----";
+            "-----END CERTIFICATE-----";
+
     @Test
-    void testDirCertsSSLContext() throws Exception{
+    void testDirCertsSSLContext() throws Exception {
         Path certDirPath = Files.createTempDirectory("certs");
         File pemFile = new File(certDirPath.toAbsolutePath().toString(), "ca.pem");
         FileOutputStream fos = new FileOutputStream(pemFile);
-        IOUtils.write(EXAMPLE_COM_PEM,fos);
+        IOUtils.write(EXAMPLE_COM_PEM, fos);
         fos.close();
         SDKBuilder builder = SDKBuilder.newBuilder().sslFactoryFromDirectory(certDirPath.toAbsolutePath().toString());
         SSLFactory sslFactory = builder.getSslFactory();
         assertNotNull(sslFactory);
-        X509Certificate[] acceptedIssuers=  sslFactory.getTrustManager().get().getAcceptedIssuers();
-        assertEquals(1, Arrays.stream(acceptedIssuers).filter(x->x.getIssuerX500Principal().getName()
+        X509Certificate[] acceptedIssuers = sslFactory.getTrustManager().get().getAcceptedIssuers();
+        assertEquals(1, Arrays.stream(acceptedIssuers).filter(x -> x.getIssuerX500Principal().getName()
                 .equals("CN=example.com")).count());
     }
 
     @Test
-    void testKeystoreSSLContext() throws Exception{
+    void testKeystoreSSLContext() throws Exception {
         KeyStore keystore = KeyStoreUtils.createKeyStore();
         keystore.setCertificateEntry("example.com", PemUtils.parseCertificate(EXAMPLE_COM_PEM).get(0));
         Path keyStorePath = Files.createTempFile("ca", "jks");
         keystore.store(new FileOutputStream(keyStorePath.toAbsolutePath().toString()), "foo".toCharArray());
-        SDKBuilder builder = SDKBuilder.newBuilder().sslFactoryFromKeyStore(keyStorePath.toAbsolutePath().toString(), "foo");
+        SDKBuilder builder = SDKBuilder.newBuilder().sslFactoryFromKeyStore(keyStorePath.toAbsolutePath().toString(),
+                "foo");
         SSLFactory sslFactory = builder.getSslFactory();
         assertNotNull(sslFactory);
-        X509Certificate[] acceptedIssuers=  sslFactory.getTrustManager().get().getAcceptedIssuers();
-        assertEquals(1, Arrays.stream(acceptedIssuers).filter(x->x.getIssuerX500Principal().getName()
+        X509Certificate[] acceptedIssuers = sslFactory.getTrustManager().get().getAcceptedIssuers();
+        assertEquals(1, Arrays.stream(acceptedIssuers).filter(x -> x.getIssuerX500Principal().getName()
                 .equals("CN=example.com")).count());
 
     }
 
-
     @Test
-    public void testPlatformPlainTextAndIDPWithSSL() throws Exception{
+    public void testPlatformPlainTextAndIDPWithSSL() throws Exception {
         sdkServicesSetup(false, true);
     }
 
     @Test
-    void testSDKServicesWithTruststore() throws Exception{
+    void testSDKServicesWithTruststore() throws Exception {
         sdkServicesSetup(true, true);
     }
 
@@ -104,7 +104,7 @@ void testCreatingSDKServicesPlainText() throws Exception {
         sdkServicesSetup(false, false);
     }
 
-    void sdkServicesSetup(boolean useSSLPlatform, boolean useSSLIDP) throws Exception{
+    void sdkServicesSetup(boolean useSSLPlatform, boolean useSSLIDP) throws Exception {
 
         HeldCertificate rootCertificate = new HeldCertificate.Builder()
                 .certificateAuthority(0)
@@ -125,9 +125,10 @@ void sdkServicesSetup(boolean useSSLPlatform, boolean useSSLIDP) throws Exceptio
         SDK.Services services = null;
         // we use the HTTP server for two things:
         // * it returns the OIDC configuration we use at bootstrapping time
-        // * it fakes out being an IDP and returns an access token when need to retrieve an access token
+        // * it fakes out being an IDP and returns an access token when need to retrieve
+        // an access token
         try (MockWebServer httpServer = new MockWebServer()) {
-            if (useSSLIDP){
+            if (useSSLIDP) {
                 httpServer.useHttps(serverHandshakeCertificates.sslSocketFactory(), false);
             }
             String oidcConfig;
@@ -138,18 +139,21 @@ void sdkServicesSetup(boolean useSSLPlatform, boolean useSSLIDP) throws Exceptio
             oidcConfig = oidcConfig
                     // if we don't do this then the library code complains that the issuer is wrong
                     .replace("<issuer>", issuer)
-                    // we want this server to be called when we fetch an access token during a service call
+                    // we want this server to be called when we fetch an access token during a
+                    // service call
                     .replace("<token_endpoint>", httpServer.url("tokens").toString());
             httpServer.enqueue(new MockResponse()
                     .setBody(oidcConfig)
-                    .setHeader("Content-type", "application/json")
-            );
+                    .setHeader("Content-type", "application/json"));
 
-            // this service returns the platform_issuer url to the SDK during bootstrapping. This
-            // tells the SDK where to download the OIDC discovery document from (our test webserver!)
+            // this service returns the platform_issuer url to the SDK during bootstrapping.
+            // This
+            // tells the SDK where to download the OIDC discovery document from (our test
+            // webserver!)
             WellKnownServiceGrpc.WellKnownServiceImplBase wellKnownService = new WellKnownServiceGrpc.WellKnownServiceImplBase() {
                 @Override
-                public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request, StreamObserver<GetWellKnownConfigurationResponse> responseObserver) {
+                public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request,
+                        StreamObserver<GetWellKnownConfigurationResponse> responseObserver) {
                     var val = Value.newBuilder().setStringValue(issuer).build();
                     var config = Struct.newBuilder().putFields("platform_issuer", val).build();
                     var response = GetWellKnownConfigurationResponse
@@ -161,31 +165,38 @@ public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request,
                 }
             };
 
-            // remember the auth headers that we received during GRPC calls to platform services
+            // remember the auth headers that we received during GRPC calls to platform
+            // services
             AtomicReference<String> servicesAuthHeader = new AtomicReference<>(null);
             AtomicReference<String> servicesDPoPHeader = new AtomicReference<>(null);
 
             // remember the auth headers that we received during GRPC calls to KAS
             AtomicReference<String> kasAuthHeader = new AtomicReference<>(null);
             AtomicReference<String> kasDPoPHeader = new AtomicReference<>(null);
-            // we use the server in two different ways. the first time we use it to actually return
-            // issuer for bootstrapping. the second time we use the interception functionality in order
+            // we use the server in two different ways. the first time we use it to actually
+            // return
+            // issuer for bootstrapping. the second time we use the interception
+            // functionality in order
             // to make sure that we are including a DPoP proof and an auth header
             ServerBuilder<?> platformServicesServerBuilder = ServerBuilder
                     .forPort(getRandomPort())
                     .directExecutor()
                     .addService(wellKnownService)
-                    .addService(new NamespaceServiceGrpc.NamespaceServiceImplBase() {})
+                    .addService(new NamespaceServiceGrpc.NamespaceServiceImplBase() {
+                    })
                     .intercept(new ServerInterceptor() {
                         @Override
-                        public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
-                            servicesAuthHeader.set(headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)));
-                            servicesDPoPHeader.set(headers.get(Metadata.Key.of("DPoP", Metadata.ASCII_STRING_MARSHALLER)));
+                        public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
+                                Metadata headers, ServerCallHandler<ReqT, RespT> next) {
+                            servicesAuthHeader.set(
+                                    headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)));
+                            servicesDPoPHeader
+                                    .set(headers.get(Metadata.Key.of("DPoP", Metadata.ASCII_STRING_MARSHALLER)));
                             return next.startCall(call, headers);
                         }
                     });
-            if (useSSLPlatform){
-                 platformServicesServerBuilder = platformServicesServerBuilder.useTransportSecurity(
+            if (useSSLPlatform) {
+                platformServicesServerBuilder = platformServicesServerBuilder.useTransportSecurity(
                         new ByteArrayInputStream(serverCertificate.certificatePem().getBytes()),
                         new ByteArrayInputStream(serverCertificate.privateKeyPkcs8Pem().getBytes()));
             }
@@ -205,14 +216,16 @@ public void rewrap(RewrapRequest request, StreamObserver<RewrapResponse> respons
                     })
                     .intercept(new ServerInterceptor() {
                         @Override
-                        public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
-                            kasAuthHeader.set(headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)));
+                        public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
+                                Metadata headers, ServerCallHandler<ReqT, RespT> next) {
+                            kasAuthHeader.set(
+                                    headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)));
                             kasDPoPHeader.set(headers.get(Metadata.Key.of("DPoP", Metadata.ASCII_STRING_MARSHALLER)));
                             return next.startCall(call, headers);
                         }
                     });
 
-            if(useSSLPlatform){
+            if (useSSLPlatform) {
                 kasServerBuilder = kasServerBuilder.useTransportSecurity(
                         new ByteArrayInputStream(serverCertificate.certificatePem().getBytes()),
                         new ByteArrayInputStream(serverCertificate.privateKeyPkcs8Pem().getBytes()));
@@ -225,12 +238,12 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
                     .clientSecret("client-id", "client-secret")
                     .platformEndpoint("localhost:" + platformServicesServer.getPort());
 
-            if(!useSSLPlatform) {
+            if (!useSSLPlatform) {
                 servicesBuilder = servicesBuilder.useInsecurePlaintextConnection(true);
             }
-            if (useSSLPlatform || useSSLIDP){
-                servicesBuilder = servicesBuilder.sslFactory(SSLFactory.builder().withTrustMaterial(rootCertificate.
-                        certificate()).build());
+            if (useSSLPlatform || useSSLIDP) {
+                servicesBuilder = servicesBuilder
+                        .sslFactory(SSLFactory.builder().withTrustMaterial(rootCertificate.certificate()).build());
             }
 
             var servicesAndComponents = servicesBuilder.buildServices();
@@ -254,7 +267,8 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
 
             httpServer.takeRequest();
 
-            // validate that we made a reasonable request to our fake IdP to get an access token
+            // validate that we made a reasonable request to our fake IdP to get an access
+            // token
             var accessTokenRequest = httpServer.takeRequest();
             assertThat(accessTokenRequest).isNotNull();
             var authHeader = accessTokenRequest.getHeader("Authorization");
@@ -262,13 +276,15 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
             var authHeaderParts = authHeader.split(" ");
             assertThat(authHeaderParts).hasSize(2);
             assertThat(authHeaderParts[0]).isEqualTo("Basic");
-            var usernameAndPassword = new String(Base64.getDecoder().decode(authHeaderParts[1]), StandardCharsets.UTF_8);
+            var usernameAndPassword = new String(Base64.getDecoder().decode(authHeaderParts[1]),
+                    StandardCharsets.UTF_8);
             assertThat(usernameAndPassword).isEqualTo("client-id:client-secret");
 
-            // validate that during the request to the namespace service we supplied a valid token
+            // validate that during the request to the namespace service we supplied a valid
+            // token
 
-            int i =0; //some race condition with testing
-            while(servicesDPoPHeader.get()==null && i < 10){
+            int i = 0; // some race condition with testing
+            while (servicesDPoPHeader.get() == null && i < 10) {
                 Thread.sleep(10);
                 i += 1;
             }
@@ -278,18 +294,20 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
             var body = new String(accessTokenRequest.getBody().readByteArray(), StandardCharsets.UTF_8);
             assertThat(body).contains("grant_type=client_credentials");
 
-            // now call KAS _on a different server_ and make sure that the interceptors provide us with auth tokens
+            // now call KAS _on a different server_ and make sure that the interceptors
+            // provide us with auth tokens
             var keyAccess = new Manifest.KeyAccess();
             keyAccess.url = "localhost:" + kasServer.getPort();
 
             try {
                 services.kas().unwrap(keyAccess, "");
             } catch (Exception ignoredException) {
-                // not going to bother making a real request with real crypto, just make sure that
+                // not going to bother making a real request with real crypto, just make sure
+                // that
                 // we have the right headers
             }
-            i =0; //some race condition with testing
-            while(kasDPoPHeader.get()==null && i < 10){
+            i = 0; // some race condition with testing
+            while (kasDPoPHeader.get() == null && i < 10) {
                 Thread.sleep(10);
                 i += 1;
             }
@@ -309,15 +327,18 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
     }
 
     /**
-     * If auth is disabled then the `platform_issuer` isn't returned during bootstrapping. The SDK
+     * If auth is disabled then the `platform_issuer` isn't returned during
+     * bootstrapping. The SDK
      * should still function without auth if auth is disabled on the server
+     * 
      * @throws IOException
      */
     @Test
     public void testSdkWithNoIssuerMakesRequests() throws IOException {
         WellKnownServiceGrpc.WellKnownServiceImplBase wellKnownService = new WellKnownServiceGrpc.WellKnownServiceImplBase() {
             @Override
-            public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request, StreamObserver<GetWellKnownConfigurationResponse> responseObserver) {
+            public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request,
+                    StreamObserver<GetWellKnownConfigurationResponse> responseObserver) {
                 // don't return a platform issuer
                 responseObserver.onNext(GetWellKnownConfigurationResponse.getDefaultInstance());
                 responseObserver.onCompleted();
@@ -332,17 +353,18 @@ public void getWellKnownConfiguration(GetWellKnownConfigurationRequest request,
                 .directExecutor()
                 .intercept(new ServerInterceptor() {
                     @Override
-                    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
+                    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
+                            Metadata headers, ServerCallHandler<ReqT, RespT> next) {
                         authHeader.set(
-                                headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER))
-                        );
+                                headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER)));
                         return next.startCall(call, headers);
                     }
                 })
                 .addService(wellKnownService)
                 .addService(new NamespaceServiceGrpc.NamespaceServiceImplBase() {
                     @Override
-                    public void getNamespace(GetNamespaceRequest request, StreamObserver<GetNamespaceResponse> responseObserver) {
+                    public void getNamespace(GetNamespaceRequest request,
+                            StreamObserver<GetNamespaceResponse> responseObserver) {
                         getNsCalled.set(true);
                         responseObserver.onNext(GetNamespaceResponse.getDefaultInstance());
                         responseObserver.onCompleted();
@@ -361,7 +383,6 @@ public void getNamespace(GetNamespaceRequest request, StreamObserver<GetNamespac
                     .build();
             assertThat(sdk.getAuthInterceptor()).isEmpty();
 
-
             try {
                 sdk.getServices().namespaces().getNamespace(GetNamespaceRequest.getDefaultInstance()).get();
             } catch (StatusRuntimeException ignored) {
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java
index a522fcb3..1dcea5ce 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java
@@ -1,17 +1,10 @@
 package io.opentdf.platform.sdk;
 
-
 import com.google.common.util.concurrent.ListenableFuture;
-import com.nimbusds.jose.crypto.MACSigner;
-import com.nimbusds.jose.crypto.MACVerifier;
-import com.nimbusds.jose.crypto.RSASSASigner;
-import com.nimbusds.jose.crypto.RSASSAVerifier;
-import com.nimbusds.jose.jwk.RSAKey;
 
 import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsRequest;
 import io.opentdf.platform.policy.attributes.GetAttributeValuesByFqnsResponse;
 import io.opentdf.platform.policy.attributes.AttributesServiceGrpc;
-import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub;
 import io.opentdf.platform.sdk.Config.KASInfo;
 import io.opentdf.platform.sdk.nanotdf.NanoTDFType;
 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
@@ -27,7 +20,6 @@
 import java.nio.charset.StandardCharsets;
 import java.security.KeyPair;
 import java.security.SecureRandom;
-import java.security.interfaces.RSAPublicKey;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.Random;
@@ -49,7 +41,8 @@ public void setup() {
 
     private static SDK.KAS kas = new SDK.KAS() {
         @Override
-        public void close() {}
+        public void close() {
+        }
 
         @Override
         public Config.KASInfo getPublicKey(Config.KASInfo kasInfo) {
@@ -84,13 +77,13 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas
         }
 
         @Override
-        public KASKeyCache getKeyCache(){
+        public KASKeyCache getKeyCache() {
             return new KASKeyCache();
         }
     };
 
     AttributesServiceGrpc.AttributesServiceFutureStub attributeGrpcStub;
-    
+
     private static ArrayList<KeyPair> keypairs = new ArrayList<>();
 
     @BeforeAll
@@ -105,7 +98,8 @@ void testSimpleTDFEncryptAndDecrypt() throws Exception {
 
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         SecureRandom secureRandom = new SecureRandom();
         byte[] key = new byte[32];
@@ -126,8 +120,7 @@ void testSimpleTDFEncryptAndDecrypt() throws Exception {
                 Config.withAutoconfigure(false),
                 Config.withKasInformation(getKASInfos()),
                 Config.withMetaData("here is some metadata"),
-                Config.withAssertionConfig(assertion1)
-        );
+                Config.withAssertionConfig(assertion1));
 
         String plainText = "this is extremely sensitive stuff!!!";
         InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes());
@@ -137,10 +130,12 @@ void testSimpleTDFEncryptAndDecrypt() throws Exception {
         tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, attributeGrpcStub);
 
         var assertionVerificationKeys = new Config.AssertionVerificationKeys();
-        assertionVerificationKeys.defaultKey = new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.HS256, key);
+        assertionVerificationKeys.defaultKey = new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.HS256,
+                key);
 
         var unwrappedData = new ByteArrayOutputStream();
-        var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, assertionVerificationKeys);
+        var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas,
+                assertionVerificationKeys);
         assertThat(reader.getManifest().payload.mimeType).isEqualTo("application/octet-stream");
 
         reader.readPayload(unwrappedData);
@@ -156,7 +151,8 @@ void testSimpleTDFWithAssertionWithRS256() throws Exception {
 
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         String assertion1Id = "assertion1";
         var keypair = CryptoUtils.generateRSAKeypair();
@@ -175,8 +171,7 @@ void testSimpleTDFWithAssertionWithRS256() throws Exception {
         Config.TDFConfig config = Config.newTDFConfig(
                 Config.withAutoconfigure(false),
                 Config.withKasInformation(getKASInfos()),
-                Config.withAssertionConfig(assertionConfig)
-        );
+                Config.withAssertionConfig(assertionConfig));
 
         String plainText = "this is extremely sensitive stuff!!!";
         InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes());
@@ -190,7 +185,8 @@ void testSimpleTDFWithAssertionWithRS256() throws Exception {
                 new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.RS256, keypair.getPublic()));
 
         var unwrappedData = new ByteArrayOutputStream();
-        var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, assertionVerificationKeys);
+        var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas,
+                assertionVerificationKeys);
         reader.readPayload(unwrappedData);
 
         assertThat(unwrappedData.toString(StandardCharsets.UTF_8))
@@ -203,7 +199,8 @@ void testSimpleTDFWithAssertionWithHS256() throws Exception {
 
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         String assertion1Id = "assertion1";
         var assertionConfig1 = new AssertionConfig();
@@ -230,8 +227,7 @@ void testSimpleTDFWithAssertionWithHS256() throws Exception {
         Config.TDFConfig config = Config.newTDFConfig(
                 Config.withAutoconfigure(false),
                 Config.withKasInformation(getKASInfos()),
-                Config.withAssertionConfig(assertionConfig1, assertionConfig2)
-        );
+                Config.withAssertionConfig(assertionConfig1, assertionConfig2));
 
         String plainText = "this is extremely sensitive stuff!!!";
         InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes());
@@ -260,7 +256,8 @@ void testSimpleTDFWithAssertionWithHS256() throws Exception {
             } else if (assertion.id.equals(assertion2Id)) {
                 assertThat(assertion.statement.format).isEqualTo("json");
                 assertThat(assertion.statement.schema).isEqualTo("urn:nato:stanag:5636:A:1:elements:json");
-                assertThat(assertion.statement.value).isEqualTo("{\"uuid\":\"f74efb60-4a9a-11ef-a6f1-8ee1a61c148a\",\"body\":{\"dataAttributes\":null,\"dissem\":null}}");
+                assertThat(assertion.statement.value).isEqualTo(
+                        "{\"uuid\":\"f74efb60-4a9a-11ef-a6f1-8ee1a61c148a\",\"body\":{\"dataAttributes\":null,\"dissem\":null}}");
                 assertThat(assertion.type).isEqualTo(AssertionConfig.Type.HandlingAssertion.toString());
             } else {
                 throw new RuntimeException("unexpected assertion id: " + assertion.id);
@@ -273,7 +270,8 @@ public void testCreatingTDFWithMultipleSegments() throws Exception {
 
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         var random = new Random();
 
@@ -281,8 +279,7 @@ public void testCreatingTDFWithMultipleSegments() throws Exception {
                 Config.withAutoconfigure(false),
                 Config.withKasInformation(getKASInfos()),
                 // use a random segment size that makes sure that we will use multiple segments
-                Config.withSegmentSize(1 + random.nextInt(20))
-        );
+                Config.withSegmentSize(1 + random.nextInt(20)));
 
         // data should be bigger than the largest segment
         var data = new byte[21 + random.nextInt(2048)];
@@ -305,8 +302,8 @@ public void testCreatingTDFWithMultipleSegments() throws Exception {
     public void testCreatingTooLargeTDF() throws Exception {
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
-
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         var random = new Random();
         var maxSize = random.nextInt(1024);
@@ -333,9 +330,12 @@ public int read(byte[] b, int off, int len) {
 
         var os = new OutputStream() {
             @Override
-            public void write(int b) {}
+            public void write(int b) {
+            }
+
             @Override
-            public void write(byte[] b, int off, int len) {}
+            public void write(byte[] b, int off, int len) {
+            }
         };
 
         var tdf = new TDF(maxSize);
@@ -356,15 +356,15 @@ public void testCreateTDFWithMimeType() throws Exception {
 
         ListenableFuture<GetAttributeValuesByFqnsResponse> resp1 = mock(ListenableFuture.class);
         lenient().when(resp1.get()).thenReturn(GetAttributeValuesByFqnsResponse.newBuilder().build());
-        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class))).thenReturn(resp1);
+        lenient().when(attributeGrpcStub.getAttributeValuesByFqns(any(GetAttributeValuesByFqnsRequest.class)))
+                .thenReturn(resp1);
 
         final String mimeType = "application/pdf";
 
         Config.TDFConfig config = Config.newTDFConfig(
                 Config.withAutoconfigure(false),
                 Config.withKasInformation(getKASInfos()),
-                Config.withMimeType(mimeType)
-        );
+                Config.withMimeType(mimeType));
 
         String plainText = "this is extremely sensitive stuff!!!";
         InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes());
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/HeaderTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/HeaderTest.java
index 649efc6a..51ca7f66 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/HeaderTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/HeaderTest.java
@@ -18,7 +18,7 @@ void setUp() {
     @Test
     void settingAndGettingMagicNumberAndVersion() {
         byte[] expected = header.getMagicNumberAndVersion();
-        assertArrayEquals(expected, new byte[]{0x4C, 0x31, 0x4C});
+        assertArrayEquals(expected, new byte[] { 0x4C, 0x31, 0x4C });
     }
 
     @Test
@@ -47,7 +47,7 @@ void settingAndGettingEphemeralKey() {
         ECCMode mode = new ECCMode((byte) 1); // Initialize the ECCMode object
         header.setECCMode(mode); // Set the ECCMode object
 
-        int keySize = mode.getECCompressedPubKeySize(mode.getEllipticCurveType());
+        int keySize = ECCMode.getECCompressedPubKeySize(mode.getEllipticCurveType());
         byte[] key = new byte[keySize]; // Ensure the key size is correct
         header.setEphemeralKey(key);
         assertArrayEquals(key, header.getEphemeralKey());
@@ -55,7 +55,7 @@ void settingAndGettingEphemeralKey() {
 
     @Test
     void settingEphemeralKeyWithInvalidSize() {
-        byte[] key = new byte[]{1, 2, 3};
+        byte[] key = new byte[] { 1, 2, 3 };
         header.setECCMode(new ECCMode((byte) 1)); // ECC mode with key size > 3
         assertThrows(IllegalArgumentException.class, () -> header.setEphemeralKey(key));
     }
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/NanoTDFHeaderTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/NanoTDFHeaderTest.java
index a68bf06a..ae289128 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/NanoTDFHeaderTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/nanotdf/NanoTDFHeaderTest.java
@@ -11,9 +11,6 @@
 
 import java.io.*;
 import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.security.*;
 import java.security.cert.CertificateException;
 import java.security.spec.InvalidKeySpecException;
@@ -21,227 +18,259 @@
 
 public class NanoTDFHeaderTest {
 
-    byte[] binding = new byte[]{(byte) 0x33, (byte) 0x31, (byte) 0x63, (byte) 0x31,
-            (byte) 0x66, (byte) 0x35, (byte) 0x35, (byte) 0x00};
-    String kasUrl = "https://api.example.com/kas";
-    String remotePolicyUrl = "https://api-develop01.develop.virtru.com/acm/api/policies/1a1d5e42-bf91-45c7-a86a-61d5331c1f55";
-
-    // Curve - "prime256v1"
-    String sdkPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
-            "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1HjFYV8D16BQszNW\n" +
-            "6Hx/JxTE53oqk5/bWaIj4qV5tOyhRANCAAQW1Hsq0tzxN6ObuXqV+JoJN0f78Em/\n" +
-            "PpJXUV02Y6Ex3WlxK/Oaebj8ATsbfaPaxrhyCWB3nc3w/W6+lySlLPn5\n" +
-            "-----END PRIVATE KEY-----";
-
-    String sdkPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
-            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFtR7KtLc8Tejm7l6lfiaCTdH+/BJ\n" +
-            "vz6SV1FdNmOhMd1pcSvzmnm4/AE7G32j2sa4cglgd53N8P1uvpckpSz5+Q==\n" +
-            "-----END PUBLIC KEY-----";
-
-    String kasPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
-            "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgu2Hmm80uUzQB1OfB\n" +
-            "PyMhWIyJhPA61v+j0arvcLjTwtqhRANCAASHCLUHY4szFiVV++C9+AFMkEL2gG+O\n" +
-            "byN4Hi7Ywl8GMPOAPcQdIeUkoTd9vub9PcuSj23I8/pLVzs23qhefoUf\n" +
-            "-----END PRIVATE KEY-----";
-
-    String kasPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
-            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhwi1B2OLMxYlVfvgvfgBTJBC9oBv\n" +
-            "jm8jeB4u2MJfBjDzgD3EHSHlJKE3fb7m/T3Lko9tyPP6S1c7Nt6oXn6FHw==\n" +
-            "-----END PUBLIC KEY-----";
-
-    byte[] compressedPubKey = new byte[]{
-            (byte) 0x03, (byte) 0x16, (byte) 0xd4, (byte) 0x7b, (byte) 0x2a, (byte) 0xd2, (byte) 0xdc, (byte) 0xf1,
-            (byte) 0x37, (byte) 0xa3, (byte) 0x9b, (byte) 0xb9, (byte) 0x7a, (byte) 0x95, (byte) 0xf8, (byte) 0x9a,
-            (byte) 0x09, (byte) 0x37, (byte) 0x47, (byte) 0xfb, (byte) 0xf0, (byte) 0x49, (byte) 0xbf, (byte) 0x3e,
-            (byte) 0x92, (byte) 0x57, (byte) 0x51, (byte) 0x5d, (byte) 0x36, (byte) 0x63, (byte) 0xa1, (byte) 0x31,
-            (byte) 0xdd
-    };
-
-    byte[] expectedHeader = new byte[]{
-            (byte) 0x4c, (byte) 0x31, (byte) 0x4c, (byte) 0x01, (byte) 0x12, (byte) 0x61, (byte) 0x70, (byte) 0x69, (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x2e,
-            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x2f, (byte) 0x6b, (byte) 0x61, (byte) 0x73, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x56, (byte) 0x61, (byte) 0x70, (byte) 0x69, (byte) 0x2d,
-            (byte) 0x64, (byte) 0x65, (byte) 0x76, (byte) 0x65, (byte) 0x6c, (byte) 0x6f, (byte) 0x70, (byte) 0x30, (byte) 0x31, (byte) 0x2e, (byte) 0x64, (byte) 0x65, (byte) 0x76, (byte) 0x65, (byte) 0x6c, (byte) 0x6f,
-            (byte) 0x70, (byte) 0x2e, (byte) 0x76, (byte) 0x69, (byte) 0x72, (byte) 0x74, (byte) 0x72, (byte) 0x75, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x2f, (byte) 0x61, (byte) 0x63, (byte) 0x6d,
-            (byte) 0x2f, (byte) 0x61, (byte) 0x70, (byte) 0x69, (byte) 0x2f, (byte) 0x70, (byte) 0x6f, (byte) 0x6c, (byte) 0x69, (byte) 0x63, (byte) 0x69, (byte) 0x65, (byte) 0x73, (byte) 0x2f, (byte) 0x31, (byte) 0x61,
-            (byte) 0x31, (byte) 0x64, (byte) 0x35, (byte) 0x65, (byte) 0x34, (byte) 0x32, (byte) 0x2d, (byte) 0x62, (byte) 0x66, (byte) 0x39, (byte) 0x31, (byte) 0x2d, (byte) 0x34, (byte) 0x35, (byte) 0x63, (byte) 0x37,
-            (byte) 0x2d, (byte) 0x61, (byte) 0x38, (byte) 0x36, (byte) 0x61, (byte) 0x2d, (byte) 0x36, (byte) 0x31, (byte) 0x64, (byte) 0x35, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x63, (byte) 0x31, (byte) 0x66,
-            (byte) 0x35, (byte) 0x35, (byte) 0x33, (byte) 0x31, (byte) 0x63, (byte) 0x31, (byte) 0x66, (byte) 0x35, (byte) 0x35, (byte) 0x00, (byte) 0x03, (byte) 0x16, (byte) 0xd4, (byte) 0x7b, (byte) 0x2a, (byte) 0xd2,
-            (byte) 0xdc, (byte) 0xf1, (byte) 0x37, (byte) 0xa3, (byte) 0x9b, (byte) 0xb9, (byte) 0x7a, (byte) 0x95, (byte) 0xf8, (byte) 0x9a, (byte) 0x09, (byte) 0x37, (byte) 0x47, (byte) 0xfb, (byte) 0xf0, (byte) 0x49,
-            (byte) 0xbf, (byte) 0x3e, (byte) 0x92, (byte) 0x57, (byte) 0x51, (byte) 0x5d, (byte) 0x36, (byte) 0x63, (byte) 0xa1, (byte) 0x31, (byte) 0xdd
-    };
-
-// TODO: Need to update the static data to fix this test
-    @Test
-    public void testNanoTDFHeaderRemotePolicy() throws IOException {
-        byte[] headerData = new byte[155];
-
-        // Construct empty header - encrypt use case
-        Header header = new Header();
-
-        ResourceLocator kasLocator = new ResourceLocator("https://api.exampl.com/kas");
-        header.setKasLocator(kasLocator);
-
-        ECCMode eccMode = new ECCMode((byte) 0x0); //no ecdsa binding and 'secp256r1'
-        header.setECCMode(eccMode);
-
-        SymmetricAndPayloadConfig payloadConfig = new SymmetricAndPayloadConfig((byte) 0x0); // no signature and AES_256_GCM_64_TAG
-        header.setPayloadConfig(payloadConfig);
-
-        PolicyInfo policyInfo = new PolicyInfo();
-        policyInfo.setRemotePolicy(remotePolicyUrl);
-        policyInfo.setPolicyBinding(binding);
-
-        header.setPolicyInfo(policyInfo);
-        header.setEphemeralKey(compressedPubKey);
-
-        int headerSize = header.getTotalSize();
-        headerSize = header.writeIntoBuffer(ByteBuffer.wrap(headerData));
-        assertEquals(headerData.length, headerSize);
-        assertTrue(Arrays.equals(headerData, expectedHeader));
-    }
-
-// TODO: Need to update the static data to fix this test
-    @Test
-    public void testNanoTDFReader() throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, CertificateException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, SignatureException {
-
-        Header header2 = new Header();
-        FileInputStream fileIn = new FileInputStream("src/test/resources/javasdknanotdf.ntdf");
-        DataInputStream dataIn = new DataInputStream(fileIn);
-
-        // Read each field of the Header object from the file
-       byte[] magicNumberAndVersion = new byte[3]; // size of magic number and version
-        dataIn.readFully(magicNumberAndVersion);
-        header2.setMagicNumberAndVersion(magicNumberAndVersion);
-
-        NanoTDFType.Protocol protocol =  NanoTDFType.Protocol.values()[dataIn.readByte()];
-
-        // Read the body length
-        int bodyLength = dataIn.readByte();
-
-        // Read the body
-        byte[] body = new byte[bodyLength];
-        dataIn.readFully(body);
-
-        // Create a new ResourceLocator object
-        ResourceLocator resourceLocator = new ResourceLocator();
-        resourceLocator.setProtocol(protocol);
-        resourceLocator.setBodyLength(bodyLength);
-        resourceLocator.setBody(body);
-        header2.setKasLocator(resourceLocator);
-
-        ECCMode eccMode2 = new ECCMode(dataIn.readByte());
-        header2.setECCMode(eccMode2);
-
-        SymmetricAndPayloadConfig payloadConfig2 = new SymmetricAndPayloadConfig(dataIn.readByte());
-        header2.setPayloadConfig(payloadConfig2);
-
-        // Read the policy type
-        int remainingBytes = dataIn.available();
-
-       // Create a byte array to hold the remaining bytes
-        byte[] remainingBytesArray = new byte[remainingBytes];
-
-       // Read the remaining bytes into the byte array
-        dataIn.readFully(remainingBytesArray);
-        PolicyInfo policyInfo = new PolicyInfo(ByteBuffer.wrap(remainingBytesArray), header2.getECCMode());
-        header2.setPolicyInfo(policyInfo);
-
-        int sizeToRead = policyInfo.getTotalSize();
-        int compressedPubKeySize = ECCMode.getECCompressedPubKeySize(header2.getECCMode().getEllipticCurveType());
-        byte[] ephemeralKey = new byte[compressedPubKeySize]; // size of compressed public key
-        System.arraycopy(remainingBytesArray, sizeToRead, ephemeralKey, 0, ephemeralKey.length);
-        header2.setEphemeralKey(ephemeralKey);
-
-        dataIn.close();
-        fileIn.close();
-
-       assertEquals(kasUrl, header2.getKasLocator().getResourceUrl());
-    }
-
-    @Test
-    public void testNanoTDFEncryption() throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, CertificateException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, SignatureException {
-        final int kGmacPayloadLength = 8;
-        final int nanoTDFIvSize = 3;
-        String policy = "{\"body\":{\"dataAttributes\":[],\"dissem\":[\"cn=virtru-user\",\"user@example.com\"]},\"uuid\":\"1a84b9c7-d59c-45ed-b092-c7ed7de73a07\"}";
-
-// Some buffers for compare.
-        byte[] compressedPubKey;
-        byte[] headerBuffer;
-        byte[] encryptedPayLoad;
-        byte[] policyBinding;
-        byte[] encryptKey;
+        byte[] binding = new byte[] { (byte) 0x33, (byte) 0x31, (byte) 0x63, (byte) 0x31,
+                        (byte) 0x66, (byte) 0x35, (byte) 0x35, (byte) 0x00 };
+        String kasUrl = "https://api.example.com/kas";
+        String remotePolicyUrl = "https://api-develop01.develop.virtru.com/acm/api/policies/1a1d5e42-bf91-45c7-a86a-61d5331c1f55";
+
+        // Curve - "prime256v1"
+        String sdkPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
+                        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1HjFYV8D16BQszNW\n" +
+                        "6Hx/JxTE53oqk5/bWaIj4qV5tOyhRANCAAQW1Hsq0tzxN6ObuXqV+JoJN0f78Em/\n" +
+                        "PpJXUV02Y6Ex3WlxK/Oaebj8ATsbfaPaxrhyCWB3nc3w/W6+lySlLPn5\n" +
+                        "-----END PRIVATE KEY-----";
+
+        String sdkPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
+                        "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFtR7KtLc8Tejm7l6lfiaCTdH+/BJ\n" +
+                        "vz6SV1FdNmOhMd1pcSvzmnm4/AE7G32j2sa4cglgd53N8P1uvpckpSz5+Q==\n" +
+                        "-----END PUBLIC KEY-----";
+
+        String kasPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
+                        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgu2Hmm80uUzQB1OfB\n" +
+                        "PyMhWIyJhPA61v+j0arvcLjTwtqhRANCAASHCLUHY4szFiVV++C9+AFMkEL2gG+O\n" +
+                        "byN4Hi7Ywl8GMPOAPcQdIeUkoTd9vub9PcuSj23I8/pLVzs23qhefoUf\n" +
+                        "-----END PRIVATE KEY-----";
+
+        String kasPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
+                        "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhwi1B2OLMxYlVfvgvfgBTJBC9oBv\n" +
+                        "jm8jeB4u2MJfBjDzgD3EHSHlJKE3fb7m/T3Lko9tyPP6S1c7Nt6oXn6FHw==\n" +
+                        "-----END PUBLIC KEY-----";
+
+        byte[] compressedPubKey = new byte[] {
+                        (byte) 0x03, (byte) 0x16, (byte) 0xd4, (byte) 0x7b, (byte) 0x2a, (byte) 0xd2, (byte) 0xdc,
+                        (byte) 0xf1,
+                        (byte) 0x37, (byte) 0xa3, (byte) 0x9b, (byte) 0xb9, (byte) 0x7a, (byte) 0x95, (byte) 0xf8,
+                        (byte) 0x9a,
+                        (byte) 0x09, (byte) 0x37, (byte) 0x47, (byte) 0xfb, (byte) 0xf0, (byte) 0x49, (byte) 0xbf,
+                        (byte) 0x3e,
+                        (byte) 0x92, (byte) 0x57, (byte) 0x51, (byte) 0x5d, (byte) 0x36, (byte) 0x63, (byte) 0xa1,
+                        (byte) 0x31,
+                        (byte) 0xdd
+        };
+
+        byte[] expectedHeader = new byte[] {
+                        (byte) 0x4c, (byte) 0x31, (byte) 0x4c, (byte) 0x01, (byte) 0x12, (byte) 0x61, (byte) 0x70,
+                        (byte) 0x69, (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
+                        (byte) 0x6c, (byte) 0x2e,
+                        (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x2f, (byte) 0x6b, (byte) 0x61, (byte) 0x73,
+                        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x56, (byte) 0x61, (byte) 0x70,
+                        (byte) 0x69, (byte) 0x2d,
+                        (byte) 0x64, (byte) 0x65, (byte) 0x76, (byte) 0x65, (byte) 0x6c, (byte) 0x6f, (byte) 0x70,
+                        (byte) 0x30, (byte) 0x31, (byte) 0x2e, (byte) 0x64, (byte) 0x65, (byte) 0x76, (byte) 0x65,
+                        (byte) 0x6c, (byte) 0x6f,
+                        (byte) 0x70, (byte) 0x2e, (byte) 0x76, (byte) 0x69, (byte) 0x72, (byte) 0x74, (byte) 0x72,
+                        (byte) 0x75, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x2f, (byte) 0x61,
+                        (byte) 0x63, (byte) 0x6d,
+                        (byte) 0x2f, (byte) 0x61, (byte) 0x70, (byte) 0x69, (byte) 0x2f, (byte) 0x70, (byte) 0x6f,
+                        (byte) 0x6c, (byte) 0x69, (byte) 0x63, (byte) 0x69, (byte) 0x65, (byte) 0x73, (byte) 0x2f,
+                        (byte) 0x31, (byte) 0x61,
+                        (byte) 0x31, (byte) 0x64, (byte) 0x35, (byte) 0x65, (byte) 0x34, (byte) 0x32, (byte) 0x2d,
+                        (byte) 0x62, (byte) 0x66, (byte) 0x39, (byte) 0x31, (byte) 0x2d, (byte) 0x34, (byte) 0x35,
+                        (byte) 0x63, (byte) 0x37,
+                        (byte) 0x2d, (byte) 0x61, (byte) 0x38, (byte) 0x36, (byte) 0x61, (byte) 0x2d, (byte) 0x36,
+                        (byte) 0x31, (byte) 0x64, (byte) 0x35, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x63,
+                        (byte) 0x31, (byte) 0x66,
+                        (byte) 0x35, (byte) 0x35, (byte) 0x33, (byte) 0x31, (byte) 0x63, (byte) 0x31, (byte) 0x66,
+                        (byte) 0x35, (byte) 0x35, (byte) 0x00, (byte) 0x03, (byte) 0x16, (byte) 0xd4, (byte) 0x7b,
+                        (byte) 0x2a, (byte) 0xd2,
+                        (byte) 0xdc, (byte) 0xf1, (byte) 0x37, (byte) 0xa3, (byte) 0x9b, (byte) 0xb9, (byte) 0x7a,
+                        (byte) 0x95, (byte) 0xf8, (byte) 0x9a, (byte) 0x09, (byte) 0x37, (byte) 0x47, (byte) 0xfb,
+                        (byte) 0xf0, (byte) 0x49,
+                        (byte) 0xbf, (byte) 0x3e, (byte) 0x92, (byte) 0x57, (byte) 0x51, (byte) 0x5d, (byte) 0x36,
+                        (byte) 0x63, (byte) 0xa1, (byte) 0x31, (byte) 0xdd
+        };
+
+        // TODO: Need to update the static data to fix this test
+        @Test
+        public void testNanoTDFHeaderRemotePolicy() throws IOException {
+                byte[] headerData = new byte[155];
+
+                // Construct empty header - encrypt use case
+                Header header = new Header();
+
+                ResourceLocator kasLocator = new ResourceLocator("https://api.exampl.com/kas");
+                header.setKasLocator(kasLocator);
+
+                ECCMode eccMode = new ECCMode((byte) 0x0); // no ecdsa binding and 'secp256r1'
+                header.setECCMode(eccMode);
+
+                SymmetricAndPayloadConfig payloadConfig = new SymmetricAndPayloadConfig((byte) 0x0); // no signature and
+                                                                                                     // AES_256_GCM_64_TAG
+                header.setPayloadConfig(payloadConfig);
+
+                PolicyInfo policyInfo = new PolicyInfo();
+                policyInfo.setRemotePolicy(remotePolicyUrl);
+                policyInfo.setPolicyBinding(binding);
+
+                header.setPolicyInfo(policyInfo);
+                header.setEphemeralKey(compressedPubKey);
+
+                int headerSize = header.getTotalSize();
+                headerSize = header.writeIntoBuffer(ByteBuffer.wrap(headerData));
+                assertEquals(headerData.length, headerSize);
+                assertTrue(Arrays.equals(headerData, expectedHeader));
+        }
 
-        SymmetricAndPayloadConfig payloadConfig = new SymmetricAndPayloadConfig((byte) 0x0);
-        int tagSize = payloadConfig.sizeOfAuthTagForCipher(payloadConfig.getCipherType());
-        byte[] tag = new byte[tagSize];
+        // TODO: Need to update the static data to fix this test
+        @Test
+        public void testNanoTDFReader()
+                        throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+                        NoSuchProviderException, CertificateException, InvalidKeyException, InvalidKeySpecException,
+                        NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, SignatureException {
 
-        ECCMode eccMode = new ECCMode((byte) 0x0); //no ecdsa binding and 'secp256r1'
-        ECKeyPair sdkECKeyPair = new ECKeyPair(eccMode.getCurveName(), ECKeyPair.ECAlgorithm.ECDH);
-        String sdkPrivateKeyForEncrypt = sdkECKeyPair.privateKeyInPEMFormat();
-        String sdkPublicKeyForEncrypt = sdkECKeyPair.publicKeyInPEMFormat();
+                Header header2 = new Header();
+                FileInputStream fileIn = new FileInputStream("src/test/resources/javasdknanotdf.ntdf");
+                DataInputStream dataIn = new DataInputStream(fileIn);
 
-        ECKeyPair kasECKeyPair = new ECKeyPair(eccMode.getCurveName(), ECKeyPair.ECAlgorithm.ECDH);
-        String kasPublicKey = kasECKeyPair.publicKeyInPEMFormat();
-        // Encrypt
-        Header header = new Header();
-
-        ResourceLocator kasLocator = new ResourceLocator("https://test.com");
-        header.setKasLocator(kasLocator);
-
-        header.setECCMode(eccMode);
-        header.setPayloadConfig(payloadConfig);
+                // Read each field of the Header object from the file
+                byte[] magicNumberAndVersion = new byte[3]; // size of magic number and version
+                dataIn.readFully(magicNumberAndVersion);
+                header2.setMagicNumberAndVersion(magicNumberAndVersion);
 
-        byte[] secret = ECKeyPair.computeECDHKey(ECKeyPair.publicKeyFromPem(kasPublicKey), ECKeyPair.privateKeyFromPem(sdkPrivateKeyForEncrypt));
-        byte[] saltValue = {'V', 'I', 'R', 'T', 'R', 'U'};
-        encryptKey = ECKeyPair.calculateHKDF(saltValue, secret);
-
-        // Encrypt the policy with key from KDF
-        int encryptedPayLoadSize = policy.length() + nanoTDFIvSize + tagSize;
-        encryptedPayLoad = new byte[encryptedPayLoadSize];
+                NanoTDFType.Protocol protocol = NanoTDFType.Protocol.values()[dataIn.readByte()];
 
-        SecureRandom secureRandom = new SecureRandom();
-        byte[] iv = new byte[nanoTDFIvSize];
-        secureRandom.nextBytes(iv);
+                // Read the body length
+                int bodyLength = dataIn.readByte();
 
-        // Adjust the span to add the IV vector at the start of the buffer
-        byte[] encryptBufferSpan = Arrays.copyOfRange(encryptedPayLoad, nanoTDFIvSize, encryptedPayLoad.length);
+                // Read the body
+                byte[] body = new byte[bodyLength];
+                dataIn.readFully(body);
 
-        AesGcm encoder = new AesGcm(encryptKey);
-        encoder.encrypt(encryptBufferSpan);
-
-        byte[] authTag = new byte[tag.length];
-        //encoder.finish(authTag);
+                // Create a new ResourceLocator object
+                ResourceLocator resourceLocator = new ResourceLocator();
+                resourceLocator.setProtocol(protocol);
+                resourceLocator.setBodyLength(bodyLength);
+                resourceLocator.setBody(body);
+                header2.setKasLocator(resourceLocator);
 
-        // Copy IV at start
-        System.arraycopy(iv, 0, encryptedPayLoad, 0, iv.length);
+                ECCMode eccMode2 = new ECCMode(dataIn.readByte());
+                header2.setECCMode(eccMode2);
 
-        // Copy tag at end
-        System.arraycopy(tag, 0, encryptedPayLoad, nanoTDFIvSize + policy.length(), tag.length);
+                SymmetricAndPayloadConfig payloadConfig2 = new SymmetricAndPayloadConfig(dataIn.readByte());
+                header2.setPayloadConfig(payloadConfig2);
 
+                // Read the policy type
+                int remainingBytes = dataIn.available();
+
+                // Create a byte array to hold the remaining bytes
+                byte[] remainingBytesArray = new byte[remainingBytes];
+
+                // Read the remaining bytes into the byte array
+                dataIn.readFully(remainingBytesArray);
+                PolicyInfo policyInfo = new PolicyInfo(ByteBuffer.wrap(remainingBytesArray), header2.getECCMode());
+                header2.setPolicyInfo(policyInfo);
 
-        // Create an encrypted policy.
-        PolicyInfo encryptedPolicy = new PolicyInfo();
-        encryptedPolicy.setEmbeddedEncryptedTextPolicy(encryptedPayLoad);
-
-        byte[] digest = encryptedPayLoad;
-        if (eccMode.isECDSABindingEnabled()) {
-            // Calculate the ecdsa binding.
-            policyBinding = ECKeyPair.computeECDSASig(digest, ECKeyPair.privateKeyFromPem(sdkPrivateKeyForEncrypt));
-            encryptedPolicy.setPolicyBinding(policyBinding);
-        } else {
-            // Calculate the gmac binding
-            byte[] gmac = Arrays.copyOfRange(digest, digest.length - kGmacPayloadLength, digest.length);
-            encryptedPolicy.setPolicyBinding(gmac);
-        }
-
-        header.setPolicyInfo(encryptedPolicy);
+                int sizeToRead = policyInfo.getTotalSize();
+                int compressedPubKeySize = ECCMode
+                                .getECCompressedPubKeySize(header2.getECCMode().getEllipticCurveType());
+                byte[] ephemeralKey = new byte[compressedPubKeySize]; // size of compressed public key
+                System.arraycopy(remainingBytesArray, sizeToRead, ephemeralKey, 0, ephemeralKey.length);
+                header2.setEphemeralKey(ephemeralKey);
 
-        compressedPubKey = ECKeyPair.compressECPublickey(sdkPublicKeyForEncrypt);
-        header.setEphemeralKey(compressedPubKey);
+                dataIn.close();
+                fileIn.close();
 
-        int headerSize = header.getTotalSize();
-        headerBuffer = new byte[headerSize];
-        int sizeWritten = header.writeIntoBuffer(ByteBuffer.wrap(headerBuffer));
-        assertEquals(sizeWritten, headerSize);
-    }
+                assertEquals(kasUrl, header2.getKasLocator().getResourceUrl());
+        }
+
+        @Test
+        public void testNanoTDFEncryption()
+                        throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+                        NoSuchProviderException, CertificateException, InvalidKeyException, InvalidKeySpecException,
+                        NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, SignatureException {
+                final int kGmacPayloadLength = 8;
+                final int nanoTDFIvSize = 3;
+                String policy = "{\"body\":{\"dataAttributes\":[],\"dissem\":[\"cn=virtru-user\",\"user@example.com\"]},\"uuid\":\"1a84b9c7-d59c-45ed-b092-c7ed7de73a07\"}";
+
+                // Some buffers for compare.
+                byte[] compressedPubKey;
+                byte[] headerBuffer;
+                byte[] encryptedPayLoad;
+                byte[] policyBinding;
+                byte[] encryptKey;
+
+                SymmetricAndPayloadConfig payloadConfig = new SymmetricAndPayloadConfig((byte) 0x0);
+                int tagSize = SymmetricAndPayloadConfig.sizeOfAuthTagForCipher(payloadConfig.getCipherType());
+                byte[] tag = new byte[tagSize];
+
+                ECCMode eccMode = new ECCMode((byte) 0x0); // no ecdsa binding and 'secp256r1'
+                ECKeyPair sdkECKeyPair = new ECKeyPair(eccMode.getCurveName(), ECKeyPair.ECAlgorithm.ECDH);
+                String sdkPrivateKeyForEncrypt = sdkECKeyPair.privateKeyInPEMFormat();
+                String sdkPublicKeyForEncrypt = sdkECKeyPair.publicKeyInPEMFormat();
+
+                ECKeyPair kasECKeyPair = new ECKeyPair(eccMode.getCurveName(), ECKeyPair.ECAlgorithm.ECDH);
+                String kasPublicKey = kasECKeyPair.publicKeyInPEMFormat();
+                // Encrypt
+                Header header = new Header();
+
+                ResourceLocator kasLocator = new ResourceLocator("https://test.com");
+                header.setKasLocator(kasLocator);
+
+                header.setECCMode(eccMode);
+                header.setPayloadConfig(payloadConfig);
+
+                byte[] secret = ECKeyPair.computeECDHKey(ECKeyPair.publicKeyFromPem(kasPublicKey),
+                                ECKeyPair.privateKeyFromPem(sdkPrivateKeyForEncrypt));
+                byte[] saltValue = { 'V', 'I', 'R', 'T', 'R', 'U' };
+                encryptKey = ECKeyPair.calculateHKDF(saltValue, secret);
+
+                // Encrypt the policy with key from KDF
+                int encryptedPayLoadSize = policy.length() + nanoTDFIvSize + tagSize;
+                encryptedPayLoad = new byte[encryptedPayLoadSize];
+
+                SecureRandom secureRandom = new SecureRandom();
+                byte[] iv = new byte[nanoTDFIvSize];
+                secureRandom.nextBytes(iv);
+
+                // Adjust the span to add the IV vector at the start of the buffer
+                byte[] encryptBufferSpan = Arrays.copyOfRange(encryptedPayLoad, nanoTDFIvSize, encryptedPayLoad.length);
+
+                AesGcm encoder = new AesGcm(encryptKey);
+                encoder.encrypt(encryptBufferSpan);
+
+                byte[] authTag = new byte[tag.length];
+                // encoder.finish(authTag);
+
+                // Copy IV at start
+                System.arraycopy(iv, 0, encryptedPayLoad, 0, iv.length);
+
+                // Copy tag at end
+                System.arraycopy(tag, 0, encryptedPayLoad, nanoTDFIvSize + policy.length(), tag.length);
+
+                // Create an encrypted policy.
+                PolicyInfo encryptedPolicy = new PolicyInfo();
+                encryptedPolicy.setEmbeddedEncryptedTextPolicy(encryptedPayLoad);
+
+                byte[] digest = encryptedPayLoad;
+                if (eccMode.isECDSABindingEnabled()) {
+                        // Calculate the ecdsa binding.
+                        policyBinding = ECKeyPair.computeECDSASig(digest,
+                                        ECKeyPair.privateKeyFromPem(sdkPrivateKeyForEncrypt));
+                        encryptedPolicy.setPolicyBinding(policyBinding);
+                } else {
+                        // Calculate the gmac binding
+                        byte[] gmac = Arrays.copyOfRange(digest, digest.length - kGmacPayloadLength, digest.length);
+                        encryptedPolicy.setPolicyBinding(gmac);
+                }
+
+                header.setPolicyInfo(encryptedPolicy);
+
+                compressedPubKey = ECKeyPair.compressECPublickey(sdkPublicKeyForEncrypt);
+                header.setEphemeralKey(compressedPubKey);
+
+                int headerSize = header.getTotalSize();
+                headerBuffer = new byte[headerSize];
+                int sizeWritten = header.writeIntoBuffer(ByteBuffer.wrap(headerBuffer));
+                assertEquals(sizeWritten, headerSize);
+        }
 }
