You do not need to export existing parameters and then re-import over them. This forces your machine to generate an RSA key and then throw it away. Therefore, specifying a key on a constructor does not matter (if you do not use a key, it will not generate one ... usually).
The public key file is a coded BLOB code.
-----BEGIN PUBLIC KEY----- MIGgMA0GCSqGSIb3DQEBAQUAA4GOADCBigKBggC8rLGlNJ17NaWArDs5mOsV6/kA 7LMpvx91cXoAshmcihjXkbWSt+xSvVry2w07Y18FlXU9/3unyYctv34yJt70SgfK Vo0QF5ksK0G/5ew1cIJM8fSxWRn+1RP9pWIEryA0otCP8EwsyknRaPoD+i+jL8zT SEwV8KLlRnx2/HYLVQkCAwEAAQ== -----END PUBLIC KEY-----
If you take the contents inside the PEM armor, it is a byte-encoded byte array.
30 81 A0 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8E 00 30 81 8A 02 81 82 00 BC AC B1 A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB 15 EB F9 00 EC B3 29 BF 1F 75 71 7A 00 B2 19 9C 8A 18 D7 91 B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63 5F 05 95 75 3D FF 7B A7 C9 87 2D BF 7E 32 26 DE F4 4A 07 CA 56 8D 10 17 99 2C 2B 41 BF E5 EC 35 70 82 4C F1 F4 B1 59 19 FE D5 13 FD A5 62 04 AF 20 34 A2 D0 8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F A3 2F CC D3 48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B 55 09 02 03 01 00 01
ITU-T X.690 defines how to read things encoded in accordance with the Basic Encoding Rules (BER), Canonical Encoding Rules (CER, which I have never seen explicitly) and "Excellent Encoding Rules" (DER). For the most part, CER BER and DER restrictions limit CER, making DER the easiest to read. ( ITU-T X.680 describes One 's abstract syntactic notation (ASN.1), which is the grammar that DER represents binary encoding)
Now we can make out a little:
30
This identifies SEQUENCE (0x10) with the CONSTRUCTED bit (0x20) set, which means that it contains other DER / tagged values. (SEQUENCE ALWAYS DESIGN IN DER)
81 A0
This next part is the length. Since it has a high bit (> 0x7F), the first byte is a length value. It indicates that the true length is encoded in the next 1 bytes ( lengthLength & 0x7F
). Therefore, the contents of this SEQUENCE is 160 bytes. (In this case, "the rest of the data", but the SEQUENCE could be contained in something else). So let's read the contents:
30 0D
We again see our 0x30
SEQUENCE ( 0x30
) with a length value of 0x0D
, so we have a 13-byte payload.
06 09 2A 86 48 86 F7 0D 01 01 01 05 00
06
- OBJECT IDENTIFIER, with a payload of 0x09
bytes. The OID has slightly non-intuitive encoding, but this is equivalent to the textual representation 1.2.840.113549.1.1.1
, which is id-rsaEncryption
( http://www.oid-info.com/get/1.2.840.113549.1.1.1 ).
That still leaves us with two bytes ( 05 00
) that we see is NULL (with a payload of 0 bytes, because, well, it's NULL).
So, so far we have
SEQUENCE SEQUENCE OID 1.2.840.113549.1.1.1 NULL 143 more bytes.
Continuation:
03 81 8E 00
03
means BIT STRING. BIT STRING is encoded as [tag] [length] [number of unused bits]. Unused bits are essentially always zero. So this is a sequence of bits, 0x8E
bytes long, and they are all used.
Technically, we have to stay there because CONSTRUCTED has not been installed. But since we know the format of this structure, we process the value as if the CONSTRUCTED bit was set like this:
30 81 8A
Here our friend CONSTRUCTED SEQUENCE again, 0x8A
bytes of payload, which conveniently matches "all that is left."
02 81 82
02
identifies INTEGER, and it has 0x82
payload bytes:
00 BC AC B1 A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB 15 EB F9 00 EC B3 29 BF 1F 75 71 7A 00 B2 19 9C 8A 18 D7 91 B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63 5F 05 95 75 3D FF 7B A7 C9 87 2D BF 7E 32 26 DE F4 4A 07 CA 56 8D 10 17 99 2C 2B 41 BF E5 EC 35 70 82 4C F1 F4 B1 59 19 FE D5 13 FD A5 62 04 AF 20 34 A2 D0 8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F A3 2F CC D3 48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B 55 09
The leading 0x00 will be a DER violation, except that the next byte has a high bit. This means that 0x00 was there to preserve the sign bit, which makes it a positive number.
02 03 01 00 01
Another INTEGER, 3 bytes, value 01 00 01
. And you're done.
SEQUENCE SEQUENCE OID 1.2.840.113549.1.1.1 NULL BIT STRING SEQUENCE INTEGER 00 BC AC ... 0B 55 09 INTEGER 01 00 01
Harvesting https://tools.ietf.org/html/rfc5280 we see that this is very similar to the SubjectPublicKeyInfo
structure:
SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING } AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } -- contains a value of the type -- registered for use with the -- algorithm object identifier value
Of course, he does not know what the RSA public key format is. But oid-info told us to check out RFC 2313 , where we see
An RSA public key shall have ASN.1 type RSAPublicKey: RSAPublicKey ::= SEQUENCE { modulus INTEGER, -- n publicExponent INTEGER -- e }
So, we say that the first INTEGER that we read is the value of the module, and the second is (public) Exponent.
DER encoding is widescreen, which is also RSAParameters encoding, but for RSAP parameters you need to remove the 0x00
leading values ββfrom the module.
Although it is not as simple as giving you the code to do this, it should be simple enough to write an RSA key parser based on this information. I would recommend you write it as internal static RSAParameters ReadRsaPublicKey(...)
and then you just need to do
RSAParameters rsaParameters = ReadRsaPublicKey(...); using (RSA rsa = RSA.Create()) { rsa.ImportParameters(rsaParameters);