使用der格式公钥生成publicKey报错

本文讲述了如何处理在项目中遇到的RSA公钥从DER格式转换为PublicKey时的异常,涉及ASN.1到X509编码转换,并提供了关键代码示例。通过解析DER编码、重构X509公钥和适配不同格式的KeyUtil,确保了公钥的正确解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近项目用到RSA公私钥对进行加解密,遇到将der格式公钥转换为PublicKey报错的问题,异常信息如下:

cn.hutool.crypto.CryptoException: InvalidKeySpecException: encoded key spec not recognized: unknown object in getInstance: org.bouncycastle.asn1.ASN1Integer
        at cn.hutool.crypto.KeyUtil.generatePublicKey(KeyUtil.java:355)
        at cn.hutool.crypto.KeyUtil.generatePublicKey(KeyUtil.java:335)
        at com.unionpay.trust.crypto.util.HsmUtilTest.testGenerateRsaAndPubKeyEncrypt(HsmUtilTest.java:95)
        at com.unionpay.trust.crypto.util.HsmUtilTest.main(HsmUtilTest.java:61)
Caused by: java.security.spec.InvalidKeySpecException: encoded key spec not recognized: unknown object in getInstance: org.bouncycastle.asn1.ASN1Integer
        at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
        at org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePublic(Unknown Source)
        at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
        at cn.hutool.crypto.KeyUtil.generatePublicKey(KeyUtil.java:353)

使用der格式公钥转换为PublicKey的方式如下:

//这里无法正常生成publickey
            // PublicKey publicKey = KeyUtil.generatePublicKey("RSA", Forms.hexStringToByte(publicKeyDerHex));
            // PublicKey publicKey = KeyUtil.generatePublicKey("RSA/ECB/PKCS1Padding", Forms.hexStringToByte(publicKeyDerHex));
            // PublicKey publicKey = KeyUtil.generatePublicKey("RSA/ECB/NoPadding", Forms.hexStringToByte(publicKeyDerHex));
            // PublicKey publicKey = KeyUtil.generatePublicKey("RSA/None/NoPadding", Forms.hexStringToByte(publicKeyDerHex));
            // PublicKey publicKey = KeyUtil.generateRSAPublicKey(Forms.hexStringToByte(publicKeyDerHex));

以上方式均无法正常生成PublicKey,报的错误都是上面的异常信息

出现错误的原因如下:

加密机产生的RSA公钥是ASN.1编码的,这里进行转换的使用需要先将ANS.1编码转换为X509编码,具体转换方式如下:

/**
     * RSA 公钥 格式转换 ANS1转X509
     * @param encodedKey   公钥
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static byte[] ansOneToX509(byte[] encodedKey) throws NoSuchAlgorithmException, InvalidKeySpecException {

        // 调用ASN1Sequence,对ASN1的RSADER编码进行解码
        ASN1Sequence asn1 = ASN1Sequence.getInstance(encodedKey);
        Enumeration<?> e = asn1.getObjects();
        BigInteger modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
        BigInteger publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();

        // 重新构造一个x509对象,并获取编码后的数据
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubkey = keyFactory.generatePublic(new RSAPublicKeySpec(modulus, publicExponent));
        byte[] x509Encoded = pubkey.getEncoded();
        return x509Encoded;
    }

经过转换之后,再讲der格式转换为PublicKey就正常了。

RSA公钥将X509编码转换为加密机可用的ASN.1编码方式如下:

/**
     * 将x509的证书公钥转换为ASN1编码
     * @param pkcs8PublicKeyByte
     * @return
     */
    public static byte[] formatPublicKeyPKCS8ToPKCS1(byte[] pkcs8PublicKeyByte) {
        ASN1Sequence publicKeyASN1Object = ASN1Sequence.getInstance(pkcs8PublicKeyByte);
        ASN1Encodable derBitStringASN1Encodable = publicKeyASN1Object.getObjectAt(1);
        DERBitString derBitStringObject = DERBitString.getInstance(derBitStringASN1Encodable);
        return derBitStringObject.getBytes();

    }


    public static String changeX509ToAns1(String publicKeyBase64){
        try {
            log.debug("changeX509ToAns1 publicKeyBase64:" + publicKeyBase64);
            //公钥加密
            String hexStr = Base64Util.base64Decode(publicKeyBase64);
            byte[] decode = hexStringToByte(hexStr);
            // //将内容转成流的方式
            ByteArrayInputStream bis = new ByteArrayInputStream(decode);
            CertificateFactory cf = null;
            cf = CertificateFactory.getInstance("X.509");
            Certificate certificate = cf.generateCertificate(bis);
            //取出公钥--这里的公钥是pkcs8的那种结构型--待核实
            PublicKey publicKey = certificate.getPublicKey();
            byte[] data = publicKey.getEncoded();
            byte[] result = formatPublicKeyPKCS8ToPKCS1(data);
            String ansEncode = Forms.byteToHexString(result);
            log.debug("changeX509ToAns1 data:" + ansEncode);
            return ansEncode;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

/**
* Base64为hutool工具类
*/
public static String base64Decode(String str) {
        return byteToHexString(Base64.decode(str));
    }

public static String byteToHexString(byte[] b) {
        if (b == null) {
            return null;
        } else {
            StringBuffer sb = new StringBuffer(b.length * 2);

            for(int i = 0; i < b.length; ++i) {
                sb.append("0123456789ABCDEF".charAt((b[i] & 240) >> 4));
                sb.append("0123456789ABCDEF".charAt((b[i] & 15) >> 0));
            }

            return sb.toString();
        }
    }


public static byte[] hexStringToByte(String hex) {
        if (hex == null) {
            return null;
        } else {
            int len = hex.length() / 2;
            hex = hex.toUpperCase();
            byte[] result = new byte[len];
            char[] achar = hex.toCharArray();

            for(int i = 0; i < len; ++i) {
                int pos = i * 2;
                result[i] = (byte)(toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
            }

            return result;
        }
    }

<think>好的,用户现在问的是如何用openssl提取RSA公钥内容到.txt文件。首先,我需要确定用户的需求。他们可能有一个私钥文件,想要从中提取公钥部分并保存为文本文件。或者他们可能有一个现有的证书,需要从中导出公钥。 接下来,我需要回忆openssl的相关命令。记得openssl rsa命令可以用来处理RSA密钥。如果用户有私钥文件,通常使用-in指定私钥文件,然后使用-pubout选项输出公钥。所以基本命令应该是openssl rsa -in private.key -pubout -out public_key.txt。 然后,可能需要考虑不同的密钥格式,比如PEM或DER。默认情况下,openssl生成的是PEM格式,所以如果用户需要其他格式,可能需要额外的参数,比如-outform DER。但用户的问题里没有提到格式转换,所以可能不需要深入这部分,不过可以提到作为可选内容。 另外,用户可能需要从证书中提取公钥。这时候需要用openssl x509命令,使用-in指定证书文件,-pubkey选项来提取公钥,然后重定向到txt文件。例如:openssl x509 -in cert.pem -pubkey -noout > public_key.txt。这时候需要注意证书文件的格式是否是PEM,如果是DER格式,可能需要加上-inform DER参数。 还需要检查用户是否可能遇到的常见问题,比如权限问题,文件路径是否正确,或者密钥是否加密。如果私钥有密码保护,openssl会提示输入密码,这时候用户需要知道密码才能提取公钥。 另外,用户可能不知道如何验证生成公钥是否正确,可以建议使用openssl rsa -pubin -in public_key.txt -text -noout来查看公钥内容,确认是否正确。 还有可能的错误场景,比如输入文件不是有效的RSA私钥,这时候openssl会报错,需要用户确认文件是否正确。或者用户可能误将证书作为私钥输入,导致命令失败,这时候需要区分不同的命令使用情况。 最后,需要确保步骤清晰,分情况说明,从私钥提取和从证书提取两种情况,并提供示例命令,这样用户可以根据自己的情况选择合适的方法。同时提醒用户替换实际的文件名,并注意文件路径的问题。</think>在 Ubuntu 系统中使用 OpenSSL 提取 RSA 公钥内容到 `.txt` 文件,需根据密钥来源类型(**私钥文件**或**证书文件**)选择不同命令: --- ### 一、从 RSA 私钥文件提取公钥 #### 1. 如果私钥是 **PEM 格式**(文件内容以 `-----BEGIN RSA PRIVATE KEY-----` 开头): ```bash openssl rsa -in private_key.pem -pubout -out public_key.txt ``` #### 2. 如果私钥是 **DER 格式**(二进制文件): ```bash openssl rsa -in private_key.der -inform DER -pubout -out public_key.txt ``` --- ### 二、从 X.509 证书文件提取公钥 #### 1. 如果证书是 **PEM 格式**(以 `-----BEGIN CERTIFICATE-----` 开头): ```bash openssl x509 -in certificate.pem -pubkey -noout > public_key.txt ``` #### 2. 如果证书是 **DER 格式**(二进制文件): ```bash openssl x509 -in certificate.der -inform DER -pubkey -noout > public_key.txt ``` --- ### 三、验证公钥内容 ```bash cat public_key.txt # 查看内容(应包含 BEGIN PUBLIC KEY 和 END PUBLIC KEY) ``` --- ### 四、参数说明 | 参数 | 作用 | |------|------| | `-pubout` | 输出公钥内容 | | `-inform DER` | 指定输入文件为 DER 格式(默认是 PEM) | | `-noout` | 禁止输出证书本身内容(仅提取公钥使用) | --- ### 五、常见问题 1. **提示 "Expecting: ANY PRIVATE KEY"** ➜ 私钥文件格式不匹配,尝试添加 `-inform DER` 参数 2. **提示 "unable to load Private Key"** ➜ 私钥可能受密码保护,需添加 `-passin pass:yourpassword` 参数 3. **生成文件无扩展名要求** `.txt` 仅为示例,实际可用 `.pem` 或自定义名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晒干的老咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值