Как загрузить открытый ключ RSA512 и показатель степени из файла .bin в python

#python #cryptography #rsa

#python #криптография #rsa

Вопрос:

У меня возникли проблемы с загрузкой открытого ключа RSA512 из файла .bin в python. Проблема в основном связана с тем, что я не знаю, в каком формате хранится ключ. Это единственное описание файла, которое мне дали.

«key.bin — необработанные двоичные байты открытого ключа и показателя степени RSA 512 бит. Используется для проверки подписи входящих пакетов. «

Я не знаю, полезно ли это, но вот байты, напечатанные на python из файла .bin.

9902c4a66b1ff76392919e7bbc35d51a5128b9da03e131b489d5ed01c1d075fc4c139a9952e9a3b040d984219a4aef0d421f6b8f9c79e1c3c35a218ecba54dc9010001

Целью настоящей задачи является создание udp-сервера, который проверяет цифровую подпись и целостность входящего пакета. В настоящее время я использую python 2.7 с библиотекой криптографии. Документацию можно найти ниже. https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/?highlight=rsa 512

Я уже пробовал приведенный ниже код, но получаю ту же ошибку для первых двух форматов и немного другую для третьего.

 with open("key.bin", "rb") as key_file:
    private_key = serialization.load_der_public_key(key_file.read(), backend=default_backend())

ValueError: Could not deserialize key data.

with open("key.bin", "rb") as key_file:
    private_key = serialization.load_pem_public_key(key_file.read(), backend=default_backend())

ValueError: Could not deserialize key data.

with open("key.bin", "rb") as key_file:
    private_key = serialization.load_ssh_public_key(key_file.read(), backend=default_backend())

ValueError: Key is not in the proper format or contains extra data.

  

Также для проверки используется алгоритм хеширования SHA256, но это, вероятно, не имеет значения.

Комментарии:

1.Рассмотрим pycryptodomex pypi.org/project/pycryptodomex

Ответ №1:

key.bin — необработанные двоичные байты открытого ключа и показателя степени RSA 512 бит. Используется для проверки подписи входящих пакетов.

В ключе RSA-512 модуль представляет собой 512-битное число, которое умещается в 64 байта или 128 шестнадцатеричных цифр. Ваш файл представлен 134 шестнадцатеричными цифрами, поэтому вполне вероятно, что 128 из этих цифр являются модулем, а остальное — общедоступный показатель степени и, возможно, метаданные.

Открытый показатель почти всегда равен 3 или 65537 = 0x010001. Учитывая, что key.bin он заканчивается на 010001 в шестнадцатеричном формате, разумно предположить, что эти последние 3 байта являются общедоступным показателем, а первые 64 байта — модулем.

 with open("key.bin", "rb") as key_file:
    n_bytes = key_file.read(64)
    e_bytes = key_file.read(3)
  

Теперь вам нужно выяснить, является ли кодировка строчной или строчной. Вы не можете отличить общедоступный показатель степени, потому что он палиндромный. Так что попробуйте обе возможности:

 n = int(n_bytes.encode('hex'), 16)
  

или

 n = int(reversed(n_bytes).encode('hex'), 16)
  

Поскольку у вас есть ключ в специальном формате, а не в стандартном формате, который используется в реальной жизни, вы, вероятно, должны использовать арифметические примитивы, а не библиотеку криптографии для работы с ключом.

Комментарии:

1. Вы можете использовать from_bytes вместо шестнадцатеричного. Эта функция также помогает принимать параметр порядка байтов. С другой стороны, ваш вариант key_file.read() немного лучше, чем моя нарезка 🙂

Ответ №2:

Ваш ключ не закодирован в известном стандарте. Вам нужно извлечь модуль и показатель степени, а затем создать из них открытый ключ.

Модуль определяет размер ключа RSA и, следовательно, равен 512 битам или 64 байтам как беззнаковое значение с большим конечным значением. Открытый показатель степени может иметь любой размер, но обычно он небольшой. Наиболее часто используемое значение экспоненты — 010001 в шестнадцатеричных числах, которое является пятым простым числом Ферма (также называемое F4, индекс на основе нуля). Однако лучше просто получить первые 64 байта и предположить, что остальные кодировки являются общедоступным показателем.

Таким образом, вы можете использовать RSAPublicNumbers для создания значений из модуля n и показателя e степени. Хитрость заключается в том, чтобы убедиться, что вы создаете модуль как положительное значение, а не отрицательное значение.


Допустим, data это двоичные данные, считанные из файла. Затем вы можете получить открытый ключ следующим образом.

Возможно, вы захотите использовать 'little' вместо 'big' , если следующее не работает (big endian — это значение RSA по умолчанию, но вы никогда не знаете). Однако в вашем случае маленькое конечное значение можно разделить, например, на 11, так что это маловероятное значение модуля (простые значения должны быть близки к половине размера ключа в битах, чтобы быть безопасными).

 modsize = 512 // 8

modBytes = data[slice(0, modsize)]
mod = int.from_bytes(modBytes, byteorder='big')

expBytes = data[slice(modsize, None)]
exp = int.from_bytes(expBytes, byteorder='big')

pubkey = RSAPublicNumbers(exp, mod).public_key(default_backend())
  

Обратите внимание, что это from_bytes было добавлено только в Python 3.2. RSAPublicNumbers немного странно в том смысле, что он принимает параметр экспоненты перед модулем. Все другие API, которые я видел, принимают модуль перед показателем степени.