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

如何将Java中的ECPublicKey转换为OpenSSH格式的字符串表示

如何将Java中的ECPublicKey转换为OpenSSH格式的字符串表示

嘿,这个需求我之前也折腾过,其实OpenSSH的ECDSA公钥格式是有固定编码规则的,咱们一步步来实现就好:

首先得明白OpenSSH的EC公钥结构:最终的字符串是「算法标识 + 空格 + Base64编码的公钥数据 + 空格 + 注释」,而Base64里面的内容是由三个带长度前缀的字节段拼接而成的:

  • 第一部分:算法名称(比如ecdsa-sha2-nistp256)的UTF-8字节,前面加4字节的大端序长度值
  • 第二部分:曲线名称(比如nistp256)的UTF-8字节,同样前面加4字节大端序长度
  • 第三部分:未压缩格式的EC公钥点字节(开头是0x04,接着是32字节的x坐标,再是32字节的y坐标)

接下来是具体的Java代码实现,直接拿过去就能用(注意要处理异常哦):

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.util.Base64;

public class ECPublicKeyToOpenSSH {
    public static String convertToOpenSSH(ECPublicKey ecPublicKey, String comment) throws Exception {
        // 1. 从ECPublicKey中提取曲线参数和公钥坐标点
        ECParameterSpec params = ecPublicKey.getParams();
        ECPoint publicPoint = ecPublicKey.getW();
        String algorithm = "ecdsa-sha2-" + params.getName();
        String curveName = params.getName();

        // 2. 组装算法名称的字节段:4字节长度前缀 + 算法名原节
        byte[] algorithmBytes = algorithm.getBytes(StandardCharsets.UTF_8);
        ByteBuffer algorithmBuffer = ByteBuffer.allocate(4 + algorithmBytes.length);
        algorithmBuffer.putInt(algorithmBytes.length);
        algorithmBuffer.put(algorithmBytes);

        // 3. 组装曲线名称的字节段:4字节长度前缀 + 曲线名字节
        byte[] curveBytes = curveName.getBytes(StandardCharsets.UTF_8);
        ByteBuffer curveBuffer = ByteBuffer.allocate(4 + curveBytes.length);
        curveBuffer.putInt(curveBytes.length);
        curveBuffer.put(curveBytes);

        // 4. 组装公钥点的字节段:0x04(未压缩标识) + 32字节x坐标 + 32字节y坐标
        BigInteger x = publicPoint.getAffineX();
        BigInteger y = publicPoint.getAffineY();
        ByteBuffer keyBuffer = ByteBuffer.allocate(1 + 32 + 32);
        keyBuffer.put((byte) 0x04);
        // 把x、y坐标处理成32字节大端序,不足补0,过长则截掉多余前缀
        keyBuffer.put(padTo32Bytes(x.toByteArray()));
        keyBuffer.put(padTo32Bytes(y.toByteArray()));

        // 5. 拼接所有字节段并做Base64编码
        ByteBuffer fullBuffer = ByteBuffer.allocate(
                algorithmBuffer.capacity() + curveBuffer.capacity() + keyBuffer.capacity()
        );
        fullBuffer.put(algorithmBuffer.array());
        fullBuffer.put(curveBuffer.array());
        fullBuffer.put(keyBuffer.array());

        String base64Key = Base64.getEncoder().encodeToString(fullBuffer.array());
        // 拼接成最终的OpenSSH格式字符串
        return String.format("%s %s %s", algorithm, base64Key, comment);
    }

    // 辅助方法:将BigInteger的字节数组统一处理为32字节大端序
    private static byte[] padTo32Bytes(byte[] input) {
        if (input.length == 32) {
            return input;
        }
        // 若输入带符号位前缀(长度超过32),则截掉前面的0x00
        if (input.length > 32) {
            return java.util.Arrays.copyOfRange(input, input.length - 32, input.length);
        }
        // 长度不足32的话,在前面补0
        byte[] padded = new byte[32];
        System.arraycopy(input, 0, padded, 32 - input.length, input.length);
        return padded;
    }
}

你可以像这样调用这个工具方法:

// 假设你已经通过其他方式获取到了ECPublicKey实例ecPublicKey
String openSshPublicKey = ECPublicKeyToOpenSSH.convertToOpenSSH(ecPublicKey, "user@example.com");
// 输出结果就会是你想要的格式:
// ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEAFuExXweUtKN3KYzoV+6eEyVfN9CLyM48FO2B9bZQ51bLtQvVo1MNVCXuW73dD2CgHXPryEwsTMyUR74GHN50= user@example.com

这里还有几个要注意的细节:

  • 曲线名称和算法标识是对应的,比如nistp256对应ecdsa-sha2-nistp256,直接从ECParameterSpec的getName()方法取就行,不用硬编码
  • 处理BigInteger字节数组时,要注意去掉可能存在的符号位前缀,同时保证长度刚好32字节,不然Base64编码后的数据会不符合OpenSSH的要求
  • 推荐用Java 8及以上的原生Base64类,兼容性和稳定性都更靠谱

备注:内容来源于stack exchange,提问作者Gili

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 11:18:07