RSA Public Key format

Reference Decoder of CRL,CRT,CSR,NEW CSR,PRIVATE KEY, PUBLIC KEY,RSA,RSA Public Key Parser

RSA Public Key

-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----

Encrypted Private Key

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
-----END RSA PRIVATE KEY-----

CRL

-----BEGIN X509 CRL-----
-----END X509 CRL-----

CRT

-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

CSR

-----BEGIN CERTIFICATE REQUEST-----
-----END CERTIFICATE REQUEST-----

NEW CSR

-----BEGIN NEW CERTIFICATE REQUEST-----
-----END NEW CERTIFICATE REQUEST-----

PEM

-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----

PKCS7

-----BEGIN PKCS7-----
-----END PKCS7-----

PRIVATE KEY

-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----

DSA KEY

-----BEGIN DSA PRIVATE KEY-----
-----END DSA PRIVATE KEY-----

Elliptic Curve

-----BEGIN EC PRIVATE KEY-----
-----END EC PRIVATE KEY-----

PGP Private Key

-----BEGIN PGP PRIVATE KEY BLOCK-----
-----END PGP PRIVATE KEY BLOCK-----

PGP Public Key

-----BEGIN PGP PUBLIC KEY BLOCK-----
-----END PGP PUBLIC KEY BLOCK-----

Starting from the decoded base64 data of an OpenSSL rsa-ssh Key, i've been able to guess a format:

  • 00 00 00 07: four byte length prefix (7 bytes)

  • 73 73 68 2d 72 73 61: "ssh-rsa"

  • 00 00 00 01: four byte length prefix (1 byte)

  • 25: RSA Exponent (e): 25

  • 00 00 01 00: four byte length prefix (256 bytes)

  • RSA Modulus (n):

      7f 9c 09 8e 8d 39 9e cc d5 03 29 8b c4 78 84 5f
      d9 89 f0 33 df ee 50 6d 5d d0 16 2c 73 cf ed 46 
      dc 7e 44 68 bb 37 69 54 6e 9e f6 f0 c5 c6 c1 d9 
      cb f6 87 78 70 8b 73 93 2f f3 55 d2 d9 13 67 32 
      70 e6 b5 f3 10 4a f5 c3 96 99 c2 92 d0 0f 05 60 
      1c 44 41 62 7f ab d6 15 52 06 5b 14 a7 d8 19 a1 
      90 c6 c1 11 f8 0d 30 fd f5 fc 00 bb a4 ef c9 2d 
      3f 7d 4a eb d2 dc 42 0c 48 b2 5e eb 37 3c 6c a0 
      e4 0a 27 f0 88 c4 e1 8c 33 17 33 61 38 84 a0 bb 
      d0 85 aa 45 40 cb 37 14 bf 7a 76 27 4a af f4 1b 
      ad f0 75 59 3e ac df cd fc 48 46 97 7e 06 6f 2d 
      e7 f5 60 1d b1 99 f8 5b 4f d3 97 14 4d c5 5e f8 
      76 50 f0 5f 37 e7 df 13 b8 a2 6b 24 1f ff 65 d1 
      fb c8 f8 37 86 d6 df 40 e2 3e d3 90 2c 65 2b 1f 
      5c b9 5f fa e9 35 93 65 59 6d be 8c 62 31 a9 9b 
      60 5a 0e e5 4f 2d e6 5f 2e 71 f3 7e 92 8f fe 8b
    

The closest validation of my theory i can find it from RFC 4253:

The "ssh-rsa" key format has the following specific encoding:

  string    "ssh-rsa"
  mpint     e
  mpint     n

Here the 'e' and 'n' parameters form the signature key blob.

But it doesn't explain the length prefixes.


Taking the random RSA PUBLIC KEY i found (in the question), and decoding the base64 into hex:

30 82 01 0a 02 82 01 01 00 fb 11 99 ff 07 33 f6 e8 05 a4 fd 3b 36 ca 68 
e9 4d 7b 97 46 21 16 21 69 c7 15 38 a5 39 37 2e 27 f3 f5 1d f3 b0 8b 2e 
11 1c 2d 6b bf 9f 58 87 f1 3a 8d b4 f1 eb 6d fe 38 6c 92 25 68 75 21 2d 
dd 00 46 87 85 c1 8a 9c 96 a2 92 b0 67 dd c7 1d a0 d5 64 00 0b 8b fd 80 
fb 14 c1 b5 67 44 a3 b5 c6 52 e8 ca 0e f0 b6 fd a6 4a ba 47 e3 a4 e8 94 
23 c0 21 2c 07 e3 9a 57 03 fd 46 75 40 f8 74 98 7b 20 95 13 42 9a 90 b0 
9b 04 97 03 d5 4d 9a 1c fe 3e 20 7e 0e 69 78 59 69 ca 5b f5 47 a3 6b a3 
4d 7c 6a ef e7 9f 31 4e 07 d9 f9 f2 dd 27 b7 29 83 ac 14 f1 46 67 54 cd 
41 26 25 16 e4 a1 5a b1 cf b6 22 e6 51 d3 e8 3f a0 95 da 63 0b d6 d9 3e 
97 b0 c8 22 a5 eb 42 12 d4 28 30 02 78 ce 6b a0 cc 74 90 b8 54 58 1f 0f 
fb 4b a3 d4 23 65 34 de 09 45 99 42 ef 11 5f aa 23 1b 15 15 3d 67 83 7a 
63 02 03 01 00 01

From RFC3447 - Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1:

A.1.1 RSA public key syntax

An RSA public key should be represented with the ASN.1 type RSAPublicKey:

  RSAPublicKey ::= SEQUENCE {
     modulus           INTEGER,  -- n
     publicExponent    INTEGER   -- e
  }

The fields of type RSAPublicKey have the following meanings:

  • modulus is the RSA modulus n.
  • publicExponent is the RSA public exponent e.

Using Microsoft's excellent (and the only real) ASN.1 documentation:

30 82 01 0a       ;SEQUENCE (0x010A bytes: 266 bytes)
|  02 82 01 01    ;INTEGER  (0x0101 bytes: 257 bytes)
|  |  00          ;leading zero because high-bit, but number is positive
|  |  fb 11 99 ff 07 33 f6 e8 05 a4 fd 3b 36 ca 68 
|  |  e9 4d 7b 97 46 21 16 21 69 c7 15 38 a5 39 37 2e 27 f3 f5 1d f3 b0 8b 2e 
|  |  11 1c 2d 6b bf 9f 58 87 f1 3a 8d b4 f1 eb 6d fe 38 6c 92 25 68 75 21 2d 
|  |  dd 00 46 87 85 c1 8a 9c 96 a2 92 b0 67 dd c7 1d a0 d5 64 00 0b 8b fd 80 
|  |  fb 14 c1 b5 67 44 a3 b5 c6 52 e8 ca 0e f0 b6 fd a6 4a ba 47 e3 a4 e8 94 
|  |  23 c0 21 2c 07 e3 9a 57 03 fd 46 75 40 f8 74 98 7b 20 95 13 42 9a 90 b0 
|  |  9b 04 97 03 d5 4d 9a 1c fe 3e 20 7e 0e 69 78 59 69 ca 5b f5 47 a3 6b a3 
|  |  4d 7c 6a ef e7 9f 31 4e 07 d9 f9 f2 dd 27 b7 29 83 ac 14 f1 46 67 54 cd 
|  |  41 26 25 16 e4 a1 5a b1 cf b6 22 e6 51 d3 e8 3f a0 95 da 63 0b d6 d9 3e 
|  |  97 b0 c8 22 a5 eb 42 12 d4 28 30 02 78 ce 6b a0 cc 74 90 b8 54 58 1f 0f 
|  |  fb 4b a3 d4 23 65 34 de 09 45 99 42 ef 11 5f aa 23 1b 15 15 3d 67 83 7a 
|  |  63 
|  02 03          ;INTEGER (3 bytes)
|     01 00 01

giving the public key modulus and exponent:

  • modulus = 0xfb1199ff0733f6e805a4fd3b36ca68...837a63
  • exponent = 65,537

Update: My expanded form of this answer in another question


You can't just change the delimiters from ---- BEGIN SSH2 PUBLIC KEY ---- to -----BEGIN RSA PUBLIC KEY----- and expect that it will be sufficient to convert from one format to another (which is what you've done in your example).

This article has a good explanation about both formats.

What you get in an RSA PUBLIC KEY is closer to the content of a PUBLIC KEY, but you need to offset the start of your ASN.1 structure to reflect the fact that PUBLIC KEY also has an indicator saying which type of key it is (see RFC 3447). You can see this using openssl asn1parse and -strparse 19, as described in this answer.

EDIT: Following your edit, your can get the details of your RSA PUBLIC KEY structure using grep -v -- ----- | tr -d '\n' | base64 -d | openssl asn1parse -inform DER:

    0:d=0  hl=4 l= 266 cons: SEQUENCE          
    4:d=1  hl=4 l= 257 prim: INTEGER           :FB1199FF0733F6E805A4FD3B36CA68E94D7B974621162169C71538A539372E27F3F51DF3B08B2E111C2D6BBF9F5887F13A8DB4F1EB6DFE386C92256875212DDD00468785C18A9C96A292B067DDC71DA0D564000B8BFD80FB14C1B56744A3B5C652E8CA0EF0B6FDA64ABA47E3A4E89423C0212C07E39A5703FD467540F874987B209513429A90B09B049703D54D9A1CFE3E207E0E69785969CA5BF547A36BA34D7C6AEFE79F314E07D9F9F2DD27B72983AC14F1466754CD41262516E4A15AB1CFB622E651D3E83FA095DA630BD6D93E97B0C822A5EB4212D428300278CE6BA0CC7490B854581F0FFB4BA3D4236534DE09459942EF115FAA231B15153D67837A63
  265:d=1  hl=2 l=   3 prim: INTEGER           :010001

To decode the SSH key format, you need to use the data format specification in RFC 4251 too, in conjunction with RFC 4253:

   The "ssh-rsa" key format has the following specific encoding:

      string    "ssh-rsa"
      mpint     e
      mpint     n

For example, at the beginning, you get 00 00 00 07 73 73 68 2d 72 73 61. The first four bytes (00 00 00 07) give you the length. The rest is the string itself: 73=s, 68=h, ... -> 73 73 68 2d 72 73 61=ssh-rsa, followed by the exponent of length 1 (00 00 00 01 25) and the modulus of length 256 (00 00 01 00 7f ...).