IPFS ping protocol

The public key data is also serialized using protobuf. How it was serialized, was a bit of a mystery at first as in the secio spec in progress the link points to https://godoc.org/github.com/libp2p/go-libp2p-crypto#Key, which doesn’t give us that much info.

Luckily an another user wrote his own implementation of secio and from that we can see the protobuf definition of the public key serialization.

I’ll write here the first few bytes in hex of the pubkey field (ID = 2), which was protobuf decoded in the last post.
08 00 12 a6 02 30 82 01 22 30

It has two fields: key type and the actual public key.

The first field key type it’s of type enum, which in protobuf has type 0. It can take 3 different values:

  • 0 = RSA
  • 1 = Ed25519
  • 2 = Secp256k1

As enum in protobuf is treated as varint, length byte is not needed. Also our values are less than 127, so the next byte is just directly the value in binary.

In our case the first two bytes were
08 00

If we write those in binary:
0x08 = 00001 000 (header, ID = 1, type = 0)
0x00 = 00000000 (data, enum value = 0)

So it’s a type 0 key, which, from the enum definition before, means it’s a RSA key.

The next field is the public key, it’s a protobuf type = 2 or string/byte array, so it has to have also length. In our case it has a length of 294 bytes. The relevant bytes for this are:
12 a6 02

In binary it would be:
0x12 = 00010 010 (header, ID = 2, type = 2)
0xa6 = 1 0100110 (length, leftmost bit is 1, we have to read the next byte as well)
0x02 = 0 0000010 (length, leftmost bit is 0, this is the end of length)

We convert the last two to the correct length (the exact explanation why/how is in the previous post):
(0x02 << 7) + (0xa6 & ~128) = 294

The next 294 bytes of data is in our case the RSA public key.
30 82 01 22 30 and so on.

If we google those bytes we get for example this post, which talks about the first bytes of ASN.1 DER RSAPublicKey.