#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, которые я видел, принимают модуль перед показателем степени.