M2Crypto - import keys from non-standard file?

2020-03-30 03:55发布

I have a file with the public exponent and modulus in it. They're not in pem or xml or der format, they're just the values written in at their offsets.

How can I make a public key out of them with M2Crypto? I also have the private key in the same format. I've managed to use code that someone posted here on Stackoverflow to generate a PEM file with php, but this seems like an extremely ridiculous way to do it.

This isn't a one-time thing either, I need to be able to read the public exponent and modulus from files in this format to check the signature.

1条回答
该账号已被封号
2楼-- · 2020-03-30 04:30

Thank you very much to Lars here: http://blog.oddbit.com/2011/05/09/signing-data-with-ssh-agent/

e is a Python long of the public exponent. n is a Python long of the public Modulus.

The code he posted was:

import M2Crypto
key = M2Crypto.RSA.new_pub_key((
    M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(hex(e)[2:])),
    M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(hex(n)[2:])),
    ))

hex will generate a hex string of the sort 0xA45E, so he's just grabbing everything after the 0x.

I'm reading the key from a file, so I don't have it as a long. I ended up using:

import M2Crypto
from binascii import hexlify 
e = f.read(4)
n = f.read(0x80)
key = M2Crypto.RSA.new_pub_key((
    M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(hexlify(e))),
    M2Crypto.m2.bn_to_mpi(M2Crypto.m2.hex_to_bn(hexlify(n))),
    ))

Worked like a charm!

The accepted format of new_pub_key, as per the documentation, needs to be

OpenSSL's MPINT format - 4-byte big-endian bit-count followed by the appropriate number of bits

I'm not sure if this is a typo, but for my exponent of (in hex) 00010001 ended up being 000003010001. I think it's a byte count, not bit count. They also stripped the first 0x00. I don't know if that's standard or if because it was an empty byte.

edit: I think I have a bit of a better understanding of the format.

If the first byte is negative, a zero byte is added to the beginning. If there are any leading (at the beginning) zero bytes, they are stripped unless the first byte would become negative, in which case, only one zero byte is left.

Some examples:

Unformatted:
\x23\x24\x25\x26
Formatted:
\x00\x00\x00\x04\x23\x24\x25\x26
Explanation:
String left as is and count of bytes packed in

Unformatted:
\x00\x23\x55\x35
Formatted:
\x00\x00\x00\x03\x23\x55\x35
Explanation:
leading zero byte removed, byte count now 3

Unformatted:
\x80\x43\x55\x27
Formatted:
\x00\x00\x00\x05\x00\x80\x43\x55\x27
Explanation:
leading zero byte added because \x80 is negative

Unformatted:
\x00\xff\x43\x23
Formatted:
\x00\x00\x00\x04\x00\xff\x43\x23
Explanation:
Leading zero byte left because \xff is negative

Unformatted:
\x23\x53\66\x00
Formatted:
\x00\x00\x00\x04\x23\x53\66\x00
Explanation:
Trailing zero byte left in string
查看更多
登录 后发表回答