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



作为标题,如何在Java中从SSH RSA公钥计算指纹? 我从sample.pub中获得了一个rsaPublicKey对象,并使用库Apache Commons Codec计算了指纹 DigestUtils.sha256Hex(rsaPublicKey.getEncoded()); 但是在使用 ssh-keygen 命令时我得到了不同的指纹 ssh-keygen -E sha256 -lf sample.pub 样本.pub 如下 ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAsuVPKUpLYSCNVIHD+e6u81IUznkDoiOvn/t56DRcutRc4OrNsZZ+Lmq49T4JCxUSmaT8PeLGS/IC946CNQzFwMh++sVoc19UUkZtRaDgiYn+HkYk8VW4IFI1dKfXomKSbX/lB+ohzLzXLVP2/UJgfBmdaE10k+6b+/Yd8YGXIeS8/Z9zToHPo0ORNSGIolgq3xMXUtfAOK/0KC6IFc/FuvuOSAG1UWup91bcm5GSXv4BWWjgFtOxCLIknYjsDah4qfrP8Olp5eUDhn/65xRcZsmRXoYe1ylhlSjJoPDFWXVs9npwqQmi3JaZtgg7xJxMu1ZcdpYxoj280zM9/6w1Lw==

您的主要问题是 SSH 用于公钥的XDR 样式编码(OpenSSH 用于计算指纹(与 Java crypto(由 X.509 正式称为SubjectPublicKeyInfo定义的 ASN.1 DER 格式(不同。事实上,我很惊讶你能够用Java读取OpenSSH.pub文件;没有直接的方法可以做到这一点。在 ssh-keygen 上查看许多现有的 Q,openssl 给出了两个不同的公钥(披露:我的(,但快速检查我认为它们中的任何一个都不是 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 dos = new DataOutputStream(os);
dos.writeInt(tag.length); dos.write(tag);
dos.writeInt(e.length); dos.write(e);
dos.writeInt(n.length); dos.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发现这个错误 - 我尝试在发布之前总是编译,我不确定我是如何错过这个的。

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

或者,如果您有.pub文件,只需读取一行的第二个空格分隔字段,从 base64 转换为byte[],对其进行哈希处理并显示。

使用它来计算公钥的指纹:

/**
* 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();
}

这将为您提供与以下内容相同的结果:

ssh-keygen -E md5 -l -f id_rsa.pub

相关内容

  • 没有找到相关文章

最新更新