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

ssh-keygen生成的RSA公钥在Java中转换报错问题排查

RSA公钥解析错误:invalid key format 问题排查与解决

问题背景

使用ssh-keygen -b 2048 -t rsa生成RSA密钥对后,在Java Servlet中读取key_rsa.pub公钥文件时先后遇到两个错误:

  1. 初始代码直接对完整公钥字符串做Base64解码,抛出Illegal base64 character错误
  2. 移除公钥开头的ssh-rsa标识和末尾注释后,又在keyFactory.generatePublic(keySpec)处抛出java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

相关代码

Servlet读取公钥代码

@WebServlet(name = "Login", urlPatterns = "/login")
public class Login extends HttpServlet {
...
        InputStream publicKeyInputStream = getClass().getClassLoader().getResourceAsStream("key_rsa.pub");
        if (publicKeyInputStream == null) {
            out.println("fail - no public key");
            out.flush();
            return;
        }
        String publicKeyString = new String(publicKeyInputStream.readAllBytes(), StandardCharsets.UTF_8);
        try {
            PublicKey publicKey = util.RSAKeyGenerator.getPublicKey(publicKeyString);
...
        } catch (Exception e) {
...
        }
}

修改后的RSAKeyGenerator.getPublicKey方法

public static PublicKey getPublicKey(String publicKeyString) throws Exception {
    publicKeyString = publicKeyString.replaceAll("ssh-rsa\\s+", "").replaceAll("\\s.*","").trim();
    byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
    return keyFactory.generatePublic(keySpec);
}

公钥文件内容

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCko/IRJIBoIN6fe3k8mCzsereXnQlTSwHutyMqZh7/JqbWJA31036I0YZUuOJ0d4WAMDWktWrfn7dkAlt+dqQtAlyzPUrqOc/euQ0iZPYhrd8Gn9jn+8WAQyt9L3LemgQ1ZWnXgNUk5Z1Y1vcbp8GsRWWLrxR7uvtbonU7QDJv5vEFnleObPqKeqobbg1iUoaXYkw0IAqhCTNW3ZvfWQic4FeHeNNVtT8XUrGyNPZkSgQ8QHsvSvNiLJ2bROhBD4AUZKBN/XRvNs+OSJM7agGroznHGxpwj7jZ0V+MH1HvHt95+4SnFAQJVfjza3lUPoMIOphq24V6hLzCr17lPECj kleber@kleber-desktop

问题原因

ssh-keygen生成的公钥是SSH格式的RSA公钥,而Java的X509EncodedKeySpec仅支持解析X.509标准格式的公钥编码,两者结构存在本质差异:

  • SSH公钥的Base64部分封装了自定义结构:先包含算法标识(ssh-rsa)的字节长度与内容,再存储公钥的模和指数数据
  • 直接解码SSH公钥的Base64内容,无法匹配X.509规范的密钥结构,因此抛出格式错误

解决方案

方案1:代码层面解析SSH公钥结构

修改getPublicKey方法,手动解析SSH公钥的内部结构,提取模和指数后构建标准RSA公钥:

public static PublicKey getPublicKey(String publicKeyString) throws Exception {
    // 移除前缀和末尾注释,保留纯Base64内容
    publicKeyString = publicKeyString.replaceAll("ssh-rsa\\s+", "").replaceAll("\\s.*", "").trim();
    byte[] decoded = Base64.getDecoder().decode(publicKeyString);
    
    try (ByteArrayInputStream bais = new ByteArrayInputStream(decoded);
         DataInputStream dis = new DataInputStream(bais)) {
        // 跳过算法标识部分(长度+内容)
        int algLen = dis.readInt();
        byte[] algBytes = new byte[algLen];
        dis.readFully(algBytes);
        
        // 读取公钥模
        int modLen = dis.readInt();
        byte[] modBytes = new byte[modLen];
        dis.readFully(modBytes);
        BigInteger modulus = new BigInteger(1, modBytes);
        
        // 读取公钥指数
        int expLen = dis.readInt();
        byte[] expBytes = new byte[expLen];
        dis.readFully(expBytes);
        BigInteger exponent = new BigInteger(1, expBytes);
        
        // 构建标准RSA公钥规范并生成公钥
        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        return keyFactory.generatePublic(spec);
    }
}

方案2:提前转换公钥格式

用工具将SSH公钥转换为X.509格式,之后直接用原代码读取:

  1. 执行以下命令转换公钥:
ssh-keygen -f key_rsa.pub -e -m PKCS8 > key_rsa_x509.pub
  1. 将转换后的key_rsa_x509.pub放入项目资源目录,原getPublicKey方法无需修改即可正常解析

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:10:41