diff --git a/.changeset/true-moose-pick.md b/.changeset/true-moose-pick.md new file mode 100644 index 0000000..526ee4f --- /dev/null +++ b/.changeset/true-moose-pick.md @@ -0,0 +1,25 @@ +--- +"evervault-java": minor +--- + +Upgrade BouncyCastle from `bcprov-jdk15on:1.70` to `bcprov-jdk18on:1.84` to +pick up outstanding security fixes and move off the unmaintained `jdk15on` +line. + +**Action required for some consumers.** The Maven coordinate changed +(`bcprov-jdk15on` → `bcprov-jdk18on`), but both jars ship classes under +identical `org.bouncycastle.*` packages. If your project also pulls in +`bcprov-jdk15on` directly or transitively via another dependency, you will +end up with both jars on the classpath — build tools don't dedupe across +different artifact ids. Classloader ordering then decides which BC "wins" +at runtime, which can cause subtle crypto failures. Evict any remaining +`bcprov-jdk15on` from your dependency tree (Gradle `exclude`, Maven +``), or add an explicit dependency on `bcprov-jdk18on` at the +version you want. + +`InvalidCipherException` gains a new public constructor +`InvalidCipherException(Throwable cause)` that preserves the underlying +cause. The existing `InvalidCipherException(InvalidCipherTextException)` +constructor is now `@Deprecated` because it leaks BouncyCastle types into +the SDK's public API; it will be removed in the next major release. Switch +any direct construction to the `Throwable` overload. diff --git a/lib/build.gradle b/lib/build.gradle index ee65110..1347b47 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -29,10 +29,11 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2' testImplementation "com.github.tomakehurst:wiremock-jre8:2.32.0" testImplementation "org.mockito:mockito-core:3.12.4" + testImplementation "org.slf4j:slf4j-nop:1.7.34" implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.guava:guava:33.6.0-android' - implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.70' + implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.84' implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.14' } diff --git a/lib/gradle.lockfile b/lib/gradle.lockfile index 18a6e47..2ed5e61 100644 --- a/lib/gradle.lockfile +++ b/lib/gradle.lockfile @@ -34,7 +34,7 @@ org.apache.httpcomponents.core5:httpcore5:5.1.1=testCompileClasspath,testRuntime org.apache.httpcomponents:httpclient:4.5.14=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.apache.httpcomponents:httpcore:4.4.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.apiguardian:apiguardian-api:1.1.0=testCompileClasspath,testRuntimeClasspath -org.bouncycastle:bcprov-jdk15on:1.70=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.bouncycastle:bcprov-jdk18on:1.84=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.eclipse.jetty.http2:http2-common:9.4.44.v20210927=testCompileClasspath,testRuntimeClasspath org.eclipse.jetty.http2:http2-hpack:9.4.44.v20210927=testCompileClasspath,testRuntimeClasspath org.eclipse.jetty.http2:http2-server:9.4.44.v20210927=testCompileClasspath,testRuntimeClasspath @@ -72,7 +72,8 @@ org.mockito:mockito-core:3.12.4=testCompileClasspath,testRuntimeClasspath org.objenesis:objenesis:3.2=testCompileClasspath,testRuntimeClasspath org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath org.ow2.asm:asm:9.2=testCompileClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.34=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-nop:1.7.34=testCompileClasspath,testRuntimeClasspath org.xmlunit:xmlunit-core:2.8.3=testCompileClasspath,testRuntimeClasspath org.xmlunit:xmlunit-legacy:2.8.3=testCompileClasspath,testRuntimeClasspath org.xmlunit:xmlunit-placeholders:2.8.3=testCompileClasspath,testRuntimeClasspath diff --git a/lib/src/main/java/com/evervault/exceptions/InvalidCipherException.java b/lib/src/main/java/com/evervault/exceptions/InvalidCipherException.java index 51016ac..5e7fbda 100644 --- a/lib/src/main/java/com/evervault/exceptions/InvalidCipherException.java +++ b/lib/src/main/java/com/evervault/exceptions/InvalidCipherException.java @@ -1,7 +1,17 @@ package com.evervault.exceptions; public class InvalidCipherException extends Exception { + /** + * @deprecated Leaks BouncyCastle into the SDK's public API. Use + * {@link #InvalidCipherException(Throwable)} instead. Retained + * for binary compatibility; scheduled for removal in v5. + */ + @Deprecated public InvalidCipherException(org.bouncycastle.crypto.InvalidCipherTextException originalException) { super(originalException.getMessage()); } + + public InvalidCipherException(Throwable cause) { + super(cause.getMessage(), cause); + } } diff --git a/lib/src/main/java/com/evervault/services/EncryptionService.java b/lib/src/main/java/com/evervault/services/EncryptionService.java index 95146b5..9744e93 100644 --- a/lib/src/main/java/com/evervault/services/EncryptionService.java +++ b/lib/src/main/java/com/evervault/services/EncryptionService.java @@ -121,8 +121,9 @@ public String encryptData(DataHeader header, byte[] generatedEcdhKey, byte[] dat try { cipher.doFinal(cipherText, len); } catch (InvalidCipherTextException e) { - // We don't want to expose Bouncy Castle to the user. - throw new InvalidCipherException(e); + // Cast to Throwable to bind to the non-deprecated overload + // (the BC-typed overload is more specific and would otherwise win). + throw new InvalidCipherException((Throwable) e); } String formatted = encryptFormatProvider.format(