Как вычислить отпечаток пальца из открытого ключа RSA?

С помощью этой команды можно сгенерировать пару открытого и закрытого ключей RSA:

ssh-keygen -f key

Теперь я хотел бы загрузить эти ключи в Python, используя модуль cryptography. Пример:

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

with open("key.pub", "rb") as f:
    datapub = f.read()

public_key = serialization.load_ssh_public_key(datapub, backend=default_backend())

Но теперь: как вы сгенерируете отпечаток пальца из этого открытого ключа? С OpenSSH это можно сделать с помощью ssh-keygen -lf key.pub. Но как сделать то же самое в Python?


person Regis May    schedule 07.11.2020    source источник
comment
Насколько я знаю, ни один отпечаток пальца не связан с экземпляром RSAPublicKey, например public_key. Отпечаток определяется в контексте формата, например. ОткрытьSSH. Здесь отпечаток пальца — это хэш SHA256 декодированного открытого ключа Base64. Одним из способов его определения может быть сериализация экземпляра RSAPublicKey в формате OpenSSH, например. с public_key.public_bytes(...) (что, конечно, приводит к datapub для опубликованного примера) и определите соответствующий хеш, например. с (но с использованием SHA256).   -  person user 9014097    schedule 08.11.2020


Ответы (1)


Прежде всего: большое спасибо, Topaco, вы дали мне важную подсказку, как создать такой отпечаток пальца. Я перепроверил это с другими источниками в WWW и не могу предоставить код для использования кем-либо.

Предположим, мы загрузили ключ и сохранили его в public_key. Затем отпечаток можно сгенерировать следующим образом:

rawKeyData = public_key.public_bytes(
    encoding=serialization.Encoding.OpenSSH,
    format=serialization.PublicFormat.OpenSSH,
)

# prepare for hashing
m = re.match("ssh-rsa ([A-Za-z0-9+/=]+)", rawKeyData.decode("utf-8"))
assert m is not None
base64BinaryData = m.group(1).encode("utf-8")
rawBinaryData = base64.b64decode(base64BinaryData)

# now create the hash
hexDigest = hashlib.md5(rawBinaryData).hexdigest()

# formatting for output similar to "ssh-keygen -l -E md5 -f <pubkeyfile>"
chunks = [ hexDigest[i:i+2] for i in range(0, len(hexDigest), 2) ]
fingerprint = str(self.__public_key.key_size) + "MD5:" + ":".join(chunks) + " (RSA)"

Это обеспечивает вывод следующим образом:

2048 MD5:bd:5a:67:a3:4c:46:9d:2c:63:78:7e:68:bc:82:eb:23 (RSA)

Единственное отличие от отпечатков пальцев OpenSSH: здесь в вывод не включается адрес электронной почты.

Некоторые замечания:

  • regex
    • I use a regular expression here to parse the output. This is done for safety as this way I ensure that the output matches the expectations of data processing here.
  • base64
    • base64 might add padding to the data.
    • base64 безопасен в использовании, так как заполнение является детерминированным.
  • md5
    • Here the MD5 output is used.
    • Вы можете безопасно заменить MD5 любым другим алгоритмом хеширования, если хотите, например. SHA256.
person Regis May    schedule 08.11.2020