You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行Jar包时加载.pem私钥报错,IDEA中运行正常

问题描述
  • 环境:Java 17、Maven 3.9.1、Spring Boot 3.0.4
  • 需求:加载.pem格式加密私钥,解密配对加密数据
  • 现象:IDEA内运行正常,但通过mvn clean install/package生成的Jar包执行时,加载私钥环节报错

加载私钥代码

public PrivateKey loadPrivateKeyFromFile(String privateKeyPath)
            throws IOException, NoSuchAlgorithmException, InvalidKeySpecException,
            OperatorCreationException, PKCSException
    {
        try (FileReader fileReader = new FileReader(privateKeyPath);
             PEMParser pemParser = new PEMParser(fileReader)) {
            Object pemObject = pemParser.readObject();
            if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) {
                PKCS8EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = (PKCS8EncryptedPrivateKeyInfo) pemObject;
                InputDecryptorProvider decryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("pass".toCharArray());
                
                /* 试过把这段代码放在多个位置,这是最后一次尝试的位置 */
                Security.addProvider(new BouncyCastleProvider());
 
                ASN1OctetString asn1OctetString= encryptedPrivateKeyInfo.decryptPrivateKeyInfo
                        (decryptorProvider).getPrivateKey();

                byte[] privateKeyBytes = asn1OctetString.getOctets();
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                return keyFactory.generatePrivate(keySpec);
            } else {
                throw new IllegalArgumentException("Unsupported PEM object: " + pemObject);
            }
        }
    }

错误位置

报错代码行:

ASN1OctetString asn1OctetString= encryptedPrivateKeyInfo.decryptPrivateKeyInfo
                        (decryptorProvider).getPrivateKey();

异常信息

org.bouncycastle.pkcs.PKCSException: unable to read encrypted data: 1.2.840.113549.1.5.13 not available: Cannot find any provider supporting 1.2.840.113549.3.7

已尝试方法

  • 添加BouncyCastle安全提供者(确认BC库存在)
  • 验证BC库已打包进Jar
  • 使用maven-shade-plugin打包
  • 尝试IDEA直接生成Jar包

POM.xml配置

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.micro</groupId>
    <artifactId>encrypt</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>encryption</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.santuario</groupId>
            <artifactId>xmlsec</artifactId>
            <version>2.1.6</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.stream</groupId>
            <artifactId>stax-api</artifactId>
            <version>1.0-2</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <shadeTestJar>true</shadeTestJar>
                            <shadedClassifierName>SHADED</shadedClassifierName>
                            <shadedArtifactAttached>true</shadedArtifactAttached>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
解决思路

1. 提前注册BouncyCastle并设置最高优先级

当前代码在创建解密器后才注册BC提供者,时机太晚。需在应用启动最开始注册,确保JDK优先使用BC的算法实现:

// 放在启动类main方法最开头
Security.insertProviderAt(new BouncyCastleProvider(), 1);

2. 升级BouncyCastle版本适配Java 17

1.70版本的BC对Java 17兼容性不足,建议升级到稳定版(如1.77+),同时更换为Java 17适配的jdk18on后缀依赖:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.77</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>1.77</version>
</dependency>

3. 修复maven-shade-plugin配置,避免SPI文件丢失

shade插件默认会覆盖META-INF/services目录下的SPI文件,导致BC算法无法被JDK识别。需添加转换器合并这些文件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <shadeTestJar>true</shadeTestJar>
                <shadedClassifierName>SHADED</shadedClassifierName>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <transformers>
                    <!-- 合并SPI服务文件 -->
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <!-- 指定Spring Boot主类 -->
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.micro.encrypt.EncryptionApplication</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

也可以直接移除shade插件,使用Spring Boot官方maven插件打包,它会自动处理依赖合并问题。

4. 明确指定KeyFactory使用BC提供者

创建KeyFactory时,显式指定BC作为提供者,避免JDK默认找不到算法:

KeyFactory keyFactory = KeyFactory.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);

内容的提问来源于stack exchange,提问作者NigDra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:58:11