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

如何将SSH公钥转换为Java的PublicKey?解决转换报错问题

SSH公钥转java.security.PublicKey解析错误解决方法

问题描述

将*.pub文件中的SSH公钥转换为java.security.PublicKey时,出现如下异常:

java.lang.IllegalArgumentException: failed to construct sequence from byte[]: unexpected end-of-contents marker

    at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
    at org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(Unknown Source)

使用的Java代码:

import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

public class PublicKeyUtil {
  private PublicKeyUtil() {}
  // (skip)
  public static PublicKey loadPublicKey(String encoded)
      throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {

    byte[] publicBytes = Base64.getDecoder().decode(encoded);
    PublicKey publicKey =
        new JcaPEMKeyConverter().getPublicKey(SubjectPublicKeyInfo.getInstance(publicBytes)); // 报错位置

    return KeyFactory.getInstance(
            publicKey.getAlgorithm(), new org.bouncycastle.jce.provider.BouncyCastleProvider())
        .generatePublic(new X509EncodedKeySpec(publicBytes));
  }
  // (skip)
}

build.gradle配置:

implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.78.1'

错误原因

SSH公钥的编码格式和X509 SubjectPublicKeyInfo的ASN.1结构不兼容:

  • SSH公钥的Base64解码后,开头包含算法标识的字节段(比如ssh-rsa的长度+字符串内容),并非纯ASN.1序列
  • 直接将该字节数组传给SubjectPublicKeyInfo.getInstance(),会因格式不匹配导致解析失败

解决方法

使用BouncyCastle提供的OpenSSHPublicKeyUtil工具类,专门处理SSH公钥的解析:

修改后的代码

import java.io.IOException;
import java.security.PublicKey;
import java.util.Base64;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class PublicKeyUtil {
    private PublicKeyUtil() {}

    public static PublicKey loadSshPublicKey(String sshPubKeyStr) throws IOException {
        // 分割SSH公钥字符串,提取Base64部分(跳过开头的算法标识,比如"ssh-rsa")
        String[] parts = sshPubKeyStr.split("\\s+");
        if (parts.length < 2) {
            throw new IllegalArgumentException("无效的SSH公钥格式");
        }
        byte[] sshPubBytes = Base64.getDecoder().decode(parts[1]);

        // 解析SSH公钥为AsymmetricKeyParameter
        AsymmetricKeyParameter keyParam = OpenSSHPublicKeyUtil.parsePublicKey(sshPubBytes);

        // 转换为java.security.PublicKey
        return new JcaPEMKeyConverter()
                .setProvider(new BouncyCastleProvider())
                .getPublicKey(keyParam);
    }

    // 测试方法
    public static void main(String[] args) throws IOException {
        // 示例:读取.pub文件的内容(一行)
        String sshPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD... 注释内容";
        PublicKey publicKey = loadSshPublicKey(sshPubKey);
        System.out.println("公钥算法:" + publicKey.getAlgorithm());
    }
}

代码说明

  1. 分割公钥字符串:SSH公钥通常格式为算法标识 Base64编码内容 注释,分割后提取中间的Base64部分
  2. 解析SSH公钥:OpenSSHPublicKeyUtil.parsePublicKey()会自动处理SSH公钥的特殊格式,提取出密钥参数
  3. 转换为JDK公钥对象:通过JcaPEMKeyConverter将BouncyCastle的密钥参数转换为标准java.security.PublicKey,之后即可调用getAlgorithm()查看算法

补充说明

  • 如果需要直接读取.pub文件,可通过Files.readString(Paths.get("xxx.pub"))获取完整的公钥字符串
  • 确保BouncyCastle Provider已正确注册,代码中通过setProvider()指定,也可提前全局注册:Security.addProvider(new BouncyCastleProvider())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 16:13:21