如何将.bin文件中的RSA512公钥和指数加载到python

时间:2019-04-13 15:33:54

标签: python cryptography rsa

我无法从.bin文件中将RSA512公钥加载到python中。问题主要是由于我不知道密钥存储在什么格式中。这是对文件的唯一描述。

“ key.bin-RSA 512位公共密钥和指数的原始二进制字节。用于验证传入的签名 数据包。”

我不知道这是否有帮助,但这是.bin文件的python中打印的字节。

9902c4a66b1ff76392919e7bbc35d51a5128b9da03e131b489d5ed01c1d075fc4c139a9952e9a3b040d984219a4aef0d421f6b8f9c79e1c3c35a218ecba54dc9010001

实际挑战的目标是构建一个udp服务器,以验证传入数据包的数字签名和完整性。目前,我正在使用带有加密库的python 2.7。文档可以在下面找到。 https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/?highlight=rsa%20512

我已经尝试过下面的代码,但是前两种格式出现相同的错误,而第三种格式则略有不同。

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,但这可能无关紧要。

2 个答案:

答案 0 :(得分: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 :(得分:1)

您的密钥未按照已知标准进行编码。您需要提取模数和指数,然后从中构建公钥。

模量定义 RSA密钥的大小,因此它是512位或64字节的无符号大端值。公共指数可以有任何大小,但通常很小。最常用的指数值为十六进制的010001,这是Fermat的第五个素数(也称为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都会在指数前采用模数。