bart bart - 17 days ago 11
Java Question

bouncycastle error "JCE cannot authenticate the provider BC" with "jar-with-dependencies"

I am creating a java standalone application that uses bouncycastle. Everything works in eclipse. I'm creating a jar with dependencies like this.

When I run the application with "java -jar myapp-0.0.1-SNAPSHOT-jar-with-dependencies.jar".

I get the following error :

java.io.IOException: exception encrypting data - java.lang.SecurityException: JCE cannot authenticate the provider BC


My code :

Security.addProvider(new BouncyCastleProvider());
String keystoreDirectory = "C:/myapp/security";
File file = new File(keystoreDirectory + "/" + PRIVATE_KEY_FILE);

if (!file.isFile()) {
try {

Configuration idOrganization = configurationBoundary.find(Configuration.ID_ORGANIZATION);

KeyStore store = KeyStore.getInstance("PKCS12", SECURITY_PROVIDER);
char[] password = KEY.toCharArray();

store.load(null, password);

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
keyPairGenerator.initialize(2048);
KeyPair pair = keyPairGenerator.generateKeyPair();

X500Name issuer = new X500Name("CN=" + idOrganization.getProperty());
BigInteger serial = BigInteger.valueOf(new SecureRandom().nextLong());
Date notBefore = new Date(System.currentTimeMillis() - 10000);
Date notAfter = new Date(System.currentTimeMillis() + 24L * 3600 * 1000 * 365);
X500Name subject = new X500Name("CN=" + idOrganization.getProperty());
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded());
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, publicKeyInfo);

ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER).build(pair.getPrivate());
X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER).getCertificate(builder.build(sigGen));

store.setKeyEntry(idOrganization.getProperty(), pair.getPrivate(), null, new java.security.cert.Certificate[]{cert});

try (FileOutputStream fos = new FileOutputStream(file)) {
store.store(fos, password); //Error here
}

} catch (Exception ex) {
logger.error("Keystore creation error", ex);
}
}


Any ideas ?
Thanks.

wsl wsl
Answer

Bouncycastle jar must be signed and cannot be placed inside fat jar. You can ship it separately and use maven-shade-plugin for this:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <artifactSet>
                    <excludes>
                        <exclude>org.bouncycastle:*:*:*</exclude>
                    </excludes>
                </artifactSet>
                <transformers>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <manifestEntries>
                            <Main-Class>com.example.Main</Main-Class>
                            <Class-Path>. ./lib/bcprov-jdk16-1.46.jar</Class-Path>
                        </manifestEntries>
                    </transformer>
                </transformers>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <shadedClassifierName>fat</shadedClassifierName>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

In ManifestResourceTransformer you define the classpath for bouncycastle jar dependency.

Comments