2

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.

Community
  • 1
  • 1
bart
  • 33
  • 1
  • 1
  • 8
  • had this issue and https://github.com/nthuemmel/executable-packer-maven-plugin saved the day – ademg Sep 14 '17 at 21:13

4 Answers4

9

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.

wsl
  • 8,875
  • 1
  • 20
  • 24
  • This indeed seems to be the problem. Shipping it separately seems to work for us. Could you please explain what function the manifestEntries have in solving the problem? Will the Class-Path entry link the fat jar to the bouncy castle jar? – nicojs Sep 05 '16 at 13:40
  • Yes, the specified bouncy castle jar classes will be loaded by classloader and they will be available for usage in runtime. The classpath manifest attribute will point to the bouncy castle provider dependecies. – wsl Sep 05 '16 at 16:36
  • Great answer except this requires the user to get the jar manually since maven doesn't copy the jars by default on package. Maven can export the JAR to the target folder for us using `maven-dependency-plugin`. Example can be found at http://stackoverflow.com/a/1751579/1016482 – rveach Sep 10 '16 at 12:48
  • 1
    Could someone please elaborate on what exactly this does and how would one customize it to work with a particular app? What should the classpath be and what to substitute for those asterisks in , for example? I'm afraid I'm too new to this area of Java to have a grasp of the logic and implications behind all this. – Sargon1 Oct 11 '16 at 13:28
  • @Sargon1 you can probably use it as is for a regular maven project. The classpath is relative to the project root (place where pom.xml lies). Leave the * as is. This will exclude all bouncy castle libs. If you want to exclude specific libs take a look here https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html – FearlessHyena Aug 08 '17 at 03:24
  • If you are looking for a Fat JAR solution without unpacking the libraries but with a special JAR classloader, take a look at [my project here](https://github.com/kriegaex/JarClassLoader). Disclaimer: I did not write the code, just package it and publish it on Maven Central and describe in my read-me how to use it. I personally use it for creating runnable uber JARs which containing BouncyCastle dependencies. Maybe it is useful for you, too. – kriegaex Aug 06 '18 at 01:04
  • What should be put in tag instead of com.example.Main? – Aliuk May 23 '19 at 10:29
1

Unfortunately JCE requires JAR with Bouncy Castle to be signed and creating executable jar ruins it. Prepare to ship BouncyCastle jar separately.

You can actually use Spring Boot or something like that - it embeds jars into fat jar, then unpacks and loads those. Or something Spring Boot-like.

alamar
  • 18,729
  • 4
  • 64
  • 97
  • Ok, That is what I thought... Do you know if there is a way to keep maven assembly plugin and ship BC jar separately ? Thanks. – bart Mar 31 '16 at 09:25
  • You can actually use Spring Boot or something like that - it embeds jars into fat jar, then unpacks and process those. Or something Spring Boot-like. – alamar Mar 31 '16 at 12:35
0

I have used this plugin for packaging a fat jar

https://github.com/nthuemmel/executable-packer-maven-plugin

it worked fine shading and using bouncy castle within a fat jar

ademg
  • 197
  • 2
  • 4
  • 17
-2

The issue is that the BouncyCastle jar is signed and must be kept as-is. For me, including the dependency in Maven with scope as 'provided' worked.

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.55</version>
        <scope>provided</scope>
    </dependency>