作为标题,如何使用Java中的SSH RSA公钥计算指纹?
我从sample.pub获取了一个rsaPublicKey对象,并使用库Apache Commons Codec计算了指纹
DigestUtils.sha256Hex(rsaPublicKey.getEncoded());
但是使用ssh-keygen命令时我得到了不同的指纹
ssh-keygen -E sha256 -lf sample.pub
sample.pub如下
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAsuVPKUpLYSCNVIHD+e6u81IUznkDoiOvn/t56DRcutRc4OrNsZZ+Lmq49T4JCxUSmaT8PeLGS/IC946CNQzFwMh++sVoc19UUkZtRaDgiYn+HkYk8VW4IFI1dKfXomKSbX/lB+ohzLzXLVP2/UJgfBmdaE10k+6b+/Yd8YGXIeS8/Z9zToHPo0ORNSGIolgq3xMXUtfAOK/0KC6IFc/FuvuOSAG1UWup91bcm5GSXv4BWWjgFtOxCLIknYjsDah4qfrP8Olp5eUDhn/65xRcZsmRXoYe1ylhlSjJoPDFWXVs9npwqQmi3JaZtgg7xJxMu1ZcdpYxoj280zM9/6w1Lw==
答案 0 :(得分:4)
您的主要问题是SSH用于公钥的 XDR样式编码(OpenSSH用于计算指纹)与Java crypto(ASN)使用的编码不同由X.509定义的.1 DER格式正式称为SubjectPublicKeyInfo
。实际上,我很惊讶您能够用Java读取OpenSSH .pub
文件;没有直接的方法可以这样做。在ssh-keygen and openssl gives two different public keys上可以看到许多现有的Q(披露:我的),但是快速检查一下,我认为它们都不是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捕获了该错误-我尝试在发布之前始终进行编译,但不确定如何错过此代码。)
第二个问题是 OpenSSH 从未以十六进制显示SHA256指纹。它最初在带有冒号的十六进制中使用 MD5 指纹;在6.8中,默认情况下,它会切换为 base64中的 SHA256 (使用传统字母而不是JSON首选的“ URLsafe”),尽管您仍然可以使用旧格式(在ssh
中使用{{ 1}}或等效的配置设置;在-oFingerprintHash=md5
中使用ssh-keygen -l
)。确定所需的一个并进行相应的编码。
或者,如果您拥有-E md5
文件,只需读取一行的第二个空格分隔的字段,将base64转换为.pub
,对其进行哈希处理并显示。
答案 1 :(得分:0)
使用它来从您的公钥计算指纹:
/**
* 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