在Python中从公钥派生SSH指纹

22 投票
3 回答
12357 浏览
提问于 2025-04-16 21:26

我想弄明白如何将一个OpenSSH的公钥,比如下面这个:

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqmEmDTNBC6O8HGCdu0MZ9zLCivDsYSttrrmlq87/YsEBpvwUTiF3UEQuFLaq5Gm+dtgxJewg/UwsZrDFxzpQhCHB6VmqrbKN2hEIkk/HJvCnAmR1ehXv8n2BWw3Jlw7Z+VgWwXAH50f2HWYqTaE4qP4Dxc4RlElxgNmlDPGXw/dYBvChYBG/RvIiTz1L+pYzPD4JR54IMmTOwjcGIJl7nk1VjKvl3D8Wgp6qejv4MfZ7Htdc99SUKcKWAeHYsjPXosSk3GlwKiS/sZi51Yca394GE7T4hZu6HTaXeZoD8+IZ7AijYn89H7EPjuu0iCAa/cjVzBsFHGszQYG+U5KfIw==

然后把它转换成一个标准的指纹,像这样:

2048 49:d3:cb:f6:00:d2:93:43:a6:27:07:ca:12:fd:5d:98 id_rsa.pub (RSA)

我试着去研究OpenSSH的源代码来理解这个过程,但我觉得太复杂了。我的第一个想法是对这个公钥文本做一个简单的MD5哈希,但结果和上面的输出不匹配。

3 个回答

0

如果你有一个使用 cryptography 库的公钥对象,这里有一个解决方案,可以生成一个 SHA256 指纹(这是现在推荐的选择)。

为了找到正确的一组字节来生成指纹,以匹配 ssh-keygen -l 给出的指纹,我花了很多时间进行故障排除。你首先需要将公钥格式化为 OpenSSH 风格,然后从这个格式化的样式中解码出 base 64 编码的字节,最后对这些字节进行哈希处理——仅仅对原始字节进行哈希处理是行不通的。

import base64

from cryptography.hazmat.primitives import hashes, serialization


def get_public_key_fingerprint(public_key):
    formatted = public_key.public_bytes(
        encoding=serialization.Encoding.OpenSSH,
        format=serialization.PublicFormat.OpenSSH,
    )
    parts = formatted.split(b" ")
    key_bytes = base64.b64decode(parts[1])

    digest = hashes.Hash(hashes.SHA256())
    digest.update(key_bytes)
    fingerprint = base64.b64encode(digest.finalize()).rstrip(b"=").decode("utf-8")

    return f"SHA256:{fingerprint}"
5

这里有一个链接,你可以在这个地址找到相关的代码和信息:https://github.com/ojarva/sshpubkeys

如果你想安装这个工具,可以在你的命令行中输入:pip install sshpubkeys

使用方法如下:

import sshpubkeys
key = sshpubkeys.SSHKey("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAqmEmDTNBC6O8H" +
    "GCdu0MZ9zLCivDsYSttrrmlq87/YsEBpvwUTiF3UEQuFLaq5Gm+dtgxJewg/UwsZrDFxz" +
    "pQhCHB6VmqrbKN2hEIkk/HJvCnAmR1ehXv8n2BWw3Jlw7Z+VgWwXAH50f2HWYqTaE4qP4" +
    "Dxc4RlElxgNmlDPGXw/dYBvChYBG/RvIiTz1L+pYzPD4JR54IMmTOwjcGIJl7nk1VjKvl" +
    "3D8Wgp6qejv4MfZ7Htdc99SUKcKWAeHYsjPXosSk3GlwKiS/sZi51Yca394GE7T4hZu6H" +
    "TaXeZoD8+IZ7AijYn89H7EPjuu0iCAa/cjVzBsFHGszQYG+U5KfIw== user@host")
print(key.bits)   # 2048
print(key.hash()) # '49:d3:cb:f6:00:d2:93:43:a6:27:07:ca:12:fd:5d:98'
49

这是经过Base64编码的密钥的MD5值:

import base64
import hashlib

def lineToFingerprint(line):
    key = base64.b64decode(line.strip().split()[1].encode('ascii'))
    fp_plain = hashlib.md5(key).hexdigest()
    return ':'.join(a+b for a,b in zip(fp_plain[::2], fp_plain[1::2]))

撰写回答