如何在Java中从SSH RSA公钥计算指纹?

如何在Java中从SSH RSA公钥计算指纹?,java,ssh-keys,public-key,java-security,rsa-key-fingerprint,Java,Ssh Keys,Public Key,Java Security,Rsa Key Fingerprint,作为标题,如何在Java中从SSH RSA公钥计算指纹? 我从sample.pub获得了一个rsaPublicKey对象,并使用ApacheCommonsCodec库计算了指纹 DigestUtils.sha256Hex(rsaPublicKey.getEncoded()); 但我在使用ssh-keygen命令时得到了不同的指纹 ssh keygen-E sha256-lf sample.pub sample.pub如下所示 ssh-rsa一个2岁的研究小组在一个2岁的研究小组中发现了

作为标题,如何在Java中从SSH RSA公钥计算指纹? 我从sample.pub获得了一个rsaPublicKey对象,并使用ApacheCommonsCodec库计算了指纹

DigestUtils.sha256Hex(rsaPublicKey.getEncoded());
但我在使用ssh-keygen命令时得到了不同的指纹

ssh keygen-E sha256-lf sample.pub
sample.pub如下所示

ssh-rsa一个2岁的研究小组在一个2岁的研究小组中发现了一个2岁的研究小组,一个2岁的研究小组,一个4岁的研究小组,一个4岁的4 4岁的4 4岁的学生,一个4岁的研究小组,一个2岁的研究小组,一个2岁的研究小组,一个2岁的研究小组,一个2岁的研究小组,一个4 4岁的学生,4 4 4年的研究4 4 4 4年的4 4 4 4 4年的4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4年的研究小组,4年的4 4 4 4年的4 4年的4 4 4 4 4 4 4 4 4 4 4 4年的4 4 4 4年的4 4 4 4 4年的4 4 4 4年的4 4 4 4 4年的4 4 4 4 4 4 4 4 4 4年4年的8年4 4 4 4年的8年8年8年的8年的8 8年的8 8 8年4 4 ZTGG7xJxMU1ZcdpYxoj280zM9/6w1Lw==

您的主要问题是,OpenSSH用于计算指纹的SSH对公钥使用的XDR样式编码与Java crypto使用的编码不同,Java crypto是X.509定义的ASN.1 DER格式,正式称为
SubjectPublicKeyInfo
。事实上,我非常惊讶您能够阅读Java中的OpenSSH
.pub
文件;没有直接的方法可以做到这一点。在(披露:我的)上可以看到许多现有的Qs,但快速检查一下,我认为它们都不是Java,所以您需要做如下操作:

byte[] n = rsapubkey.getModulus().toByteArray(); // Java is 2sC bigendian
byte[] e = rsapubkey.getPublicExponent().toByteArray(); // and so is SSH
byte[] tag = "ssh-rsa".getBytes(); // charset very rarely matters here
ByteArrayOutputStream os = new ByteArrayOutputStream();
DataOutputStream do = new DataOutputStream(os);
do.writeInt(tag.length); do.write(tag);
do.writeInt(e.length); do.write(e);
do.writeInt(n.length); do.write(n);
byte[] encoded = os.toByteArray();
// now hash that (you don't really need Apache) 
// assuming SHA256-base64 (see below)
MessageDigest digest = MessageDigest.getInstance("SHA256");
byte[] result = digest.digest(encoded);
String output = Base64.getEncoder().encodeToString(result);
(旁白:感谢linc01n发现了这个bug——我总是在发布之前进行编译,但我不确定我怎么会错过这个。)

第二个问题是,OpenSSH从未以十六进制显示SHA256指纹。它最初使用带有冒号的十六进制MD5指纹;在6.8中,默认情况下,它在base64中切换为SHA256(使用传统的字母表,而不是JSON首选的“URLsafe”字母表),尽管您仍然可以使用较旧的形式(在
ssh
中使用
-oFingerprintHash=md5
或等效的配置设置;在
ssh-keygen-l
中使用
-E md5
)。确定您想要哪一个并相应地编码


或者,如果您有
.pub
文件,只需读取一行中以空格分隔的第二个字段,将base64转换为
字节[]
,对其进行散列,然后显示。

使用此选项从公钥计算指纹:

    /**
     * Calculate fingerprint
     *
     * @param publicKey public key
     * @return fingerprint
     */
    public static String calculateFingerprint(String publicKey) {
        String derFormat = publicKey.split(" ")[1].trim();
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("Could not get fingerprint", e);
        }
        byte[] digest = messageDigest.digest(Base64.getDecoder().decode(derFormat));
        final StringBuilder toRet = new StringBuilder();
        for (int i = 0; i < digest.length; i++) {
            if (i != 0) toRet.append(":");
            int b = digest[i] & 0xff;
            String hex = Integer.toHexString(b);
            if (hex.length() == 1) toRet.append("0");
            toRet.append(hex);
        }
        return toRet.toString();
    }

如果默认的平台字符集是UTF-16怎么办?然后“ssh-rsa”被错误地编码。“修复”:-:-)哈哈,好吧,你赢了。我建议将变量名“do”更新为非关键字的名称:)有办法吗?我有指纹,我需要rsa密钥。可能吗?不可能。指纹由哈希函数计算。如果你知道什么是杂烩,你就不会问这样的问题。
ssh-keygen -E md5 -l -f id_rsa.pub