【问题标题】:bouncycastle error "JCE cannot authenticate the provider BC" with "jar-with-dependencies"bouncycastle 错误“JCE 无法验证提供者 BC”与“jar-with-dependencies”
【发布时间】:2016-03-31 09:15:03
【问题描述】:

我正在创建一个 java 独立应用程序,它使用 bouncycastle。 一切都在 Eclipse 中运行。我正在创建一个带有依赖项的jar,例如this

当我使用 "java -jar myapp-0.0.1-SNAPSHOT-jar-with-dependencies.jar" 运行应用程序时。

我收到以下错误:

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

我的代码:

    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);
        }
    }

有什么想法吗? 谢谢。

【问题讨论】:

标签: java bouncycastle executable-jar


【解决方案1】:

Bouncycastle jar 必须签名,并且不能放在胖 jar 中。 您可以单独发布它并为此使用 maven-shade-plugin:

        <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>

在 ManifestResourceTransformer 中定义 bouncycastle jar 依赖项的类路径。

【讨论】:

  • 这似乎确实是问题所在。分开运输似乎对我们有用。您能否解释一下 manifestEntries 在解决问题中的作用?类路径条目是否会将胖罐子链接到充气城堡罐子?
  • 是的,指定的充气城堡 jar 类将由类加载器加载,并且可以在运行时使用。类路径清单属性将指向充气城堡提供程序依赖项。
  • 很好的答案,除了这需要用户手动获取 jar,因为 maven 默认情况下不会在包上复制 jar。 Maven 可以使用maven-dependency-plugin 为我们将 JAR 导出到目标文件夹。示例可以在stackoverflow.com/a/1751579/1016482 找到
  • 有人可以详细说明这到底是做什么的,以及如何自定义它以与特定的应用程序一起使用?例如,类路径应该是什么以及用什么代替 中的那些星号?恐怕我对 Java 的这个领域太陌生了,无法掌握这一切背后的逻辑和含义。
  • @Sargon1 您可能可以将它原样用于常规 maven 项目。类路径相对于项目根目录(pom.xml 所在的位置)。将 * 保留原样。这将排除所有充气城堡库。如果您想排除特定库,请查看此处maven.apache.org/plugins/maven-shade-plugin/examples/…
【解决方案2】:

不幸的是,JCE 需要对带有 Bouncy Castle 的 JAR 进行签名,而创建可执行 jar 会破坏它。准备单独运送 BouncyCastle 罐子。

您实际上可以使用 Spring Boot 或类似的东西 - 它将 jar 嵌入到 fat jar 中,然后解包并加载它们。或者类似 Spring Boot 的东西。

【讨论】:

  • 好吧,我就是这么想的……你知道有没有办法让maven组装插件和BC jar分开运输?谢谢。
  • 您实际上可以使用 Spring Boot 或类似的东西 - 它将 jar 嵌入到 fat jar 中,然后解压缩并处理它们。或者类似 Spring Boot 的东西。
【解决方案3】:

我用这个插件来打包一个胖罐子

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

它可以很好地着色并在肥罐中使用充气城堡

【讨论】:

    【解决方案4】:

    问题在于 BouncyCastle jar 已签名并且必须保持原样。对我来说,包括范围为“提供”的 Maven 中的依赖项是有效的。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-10-02
      相关资源
      最近更新 更多