I have the modulus & exponent of an RSA public key embedded into a binary file, and I am trying to extract the entire blob and create a usable .pem public key.
Currently, I am extracting the full 260 bytes (4 bytes for the exponent, 256 bytes for the modulus) and encoding as base64. I am doing that using the following shell command :
tail -c $((filesize - start_of_key_data)) filename | head -c $size_of_key_data | base64 > outkey
This gives me the following string :
<<<<<< modulus & exponent extracted from binary file, base64-encoded >>>>>>
tZyrQA6cZFJfVm6FyXwtZaLQYg8EecuO+ObrHTwc8JO+XrgnpNAdmlhbAEPxSNnjwhNnbYGYGL4F
vzmnZXzZU71Key42HQPh1k2Zx1UDbrH5ciODKx1ZbuEx8K24SHnL1nY/H75hwhT/ZRRVGQDvYDT+
sgzw2vmV66+dflw1Zs8BLhqjLjczdHvjeVXsDRJ9Mvvd/dhFH8UlTf4JpLGya9nsNIfNBBIf1Lll
RWwCTiEIbaOMgWcLjLV/2tk/j5Dra/oQnVf/2hVsEF/hXEx41YjeEW/warweoDVG7zaxrHEc/k/r
ZCUCZKxf8nBKdqax/gRICvkG6e5xg2GQw0W/ZwABAAE=
Now, when I take the key.pem keypair that the modulus & exponent were originally extracted from, and display the public portion like so
openssl rsa -in key.pem -pubout -out pubkey.pem
I get this string (I have omitted the header & footer lines :
<<<<<<<<< valid public key data extracted from keypair >>>>>>>>>
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtZyrQA6cZFJfVm6FyXwt
ZaLQYg8EecuO+ObrHTwc8JO+XrgnpNAdmlhbAEPxSNnjwhNnbYGYGL4FvzmnZXzZ
U71Key42HQPh1k2Zx1UDbrH5ciODKx1ZbuEx8K24SHnL1nY/H75hwhT/ZRRVGQDv
YDT+sgzw2vmV66+dflw1Zs8BLhqjLjczdHvjeVXsDRJ9Mvvd/dhFH8UlTf4JpLGy
a9nsNIfNBBIf1LllRWwCTiEIbaOMgWcLjLV/2tk/j5Dra/oQnVf/2hVsEF/hXEx4
1YjeEW/warweoDVG7zaxrHEc/k/rZCUCZKxf8nBKdqax/gRICvkG6e5xg2GQw0W/
ZwIDAQAB
You can see that the key data which I have extracted and base64-encoded myself is actually present in the data of the valid public key data extracted from the key.pem using openssl. However there are 45 characters at the beginning, that my own extracted data does not have -
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
and the last 8 characters also differ.
ZwIDAQAB
Can anybody offer some advice on how to convert a modulus and exponent into a usable public key?
(the goal is to do this in a bash script, not python or C as I've seen many suggest.)
At the center of the RSA cryptosystem is the RSA modulus N. It is a positive integer which equals the product of two distinct prime numbers p and q: RSA modulus: N = pq.
Public key contains modulus and public exponent. Modulus (n) is the product of two prime numbers used to generate the key pair. Public exponent (d) is the exponent used on signed / encoded data to decode the original value.
The private key consists of the modulus (n) and the private exponent (d). The first of two prime numbers that are multiplied together to produce the modulus. Called p. The second of two prime numbers that are multiplied together to produce the modulus.
Command which you used, openssl rsa -in key.pem -pubout -out pubkey.pem
, produces the ASN.1 structure like this:
SEQUENCE(2 elem)
SEQUENCE(2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.1.1
NULL
BIT STRING(1 elem)
SEQUENCE(2 elem)
INTEGER(2048 bit) 229263895356027367204242482830890190076375310244080661230946245232688…
INTEGER 65537
(You can see the structure with openssl asn1parse -in pubkey.pem
, or using an online ASN.1 decoder).
It contents:
If you have the modulus and exponent bytes correctly collected, you can construct the the public key in form, understandable by OpenSSL, by concatenating these four things. You already have the first longer header. The "middle header" is '02 03':
If your modulus is 2048 bits (256 bytes) and exponent 3 bytes (so that the length fields remain valid), the PEM file can be produced by concatenating these four:
<header> <modulus> 0x02 0x03 <exponent>
That is why the last bytes from the binary dump differ from the OpenSSL output: the extracted 260 bytes do not contain 02 03
, but instead record 65537 as 00 01 00 01
(not 01 00 01
as in ASN.1 encoding).
To summarize, you can produce the PEM file like this:
Convert your extracted modulus+exponent back from base64 and extract them (note the 257 byte offset to skip the leading zero byte of 65537!):
echo 'tZyrQA6cZFJfVm6FyXwtZaLQYg8EecuO+ObrHTwc8JO+XrgnpNAdmlhbAEPxSNnjwhNnbYGYGL4FvzmnZXzZU71Key42HQPh1k2Zx1UDbrH5ciODKx1ZbuEx8K24SHnL1nY/H75hwhT/ZRRVGQDvYDT+sgzw2vmV66+dflw1Zs8BLhqjLjczdHvjeVXsDRJ9Mvvd/dhFH8UlTf4JpLGya9nsNIfNBBIf1LllRWwCTiEIbaOMgWcLjLV/2tk/j5Dra/oQnVf/2hVsEF/hXEx41YjeEW/warweoDVG7zaxrHEc/k/rZCUCZKxf8nBKdqax/gRICvkG6e5xg2GQw0W/ZwABAAE=' | base64 -d > modulus-exp.bin
dd if=modulus-exp.bin of=modulus.bin bs=1 count=256
dd if=modulus-exp.bin of=exponent.bin bs=1 skip=257 count=3
Create the headers:
echo 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA' | base64 -d > header.bin
echo '02 03' | xxd -r -p > mid-header.bin
Concatenate them together:
cat header.bin modulus.bin mid-header.bin exponent.bin > key.der
Convert to PEM:
openssl pkey -inform der -outform pem -pubin -in key.der -out key.pem
Test that you get the working key - by checking it with ASN.1 decoder, or by
openssl asn1parse -in key.pem
openssl asn1parse -in key.pem -strparse 19
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With