4

I came across a PGP public key that seems invalid. The key is a secp256k1 public key that supported by GPG. In fact, GPG allows importing that key even if it has an invalid secp256k1 public key inside.

Running --list-packets on the key shows that the pkey starts with a 46 prefix. All other secp256k1 public keys I generated or found online start with 02 if they are compressed and 04 if they are not. Starting with these two prefixes is in line with the sec-1 standard but there's nothing about a 46 prefix.

# gpg --list-packets --verbose public_key_invalid.gpg

gpg: enabled compatibility flags:
# off=0 ctb=98 tag=6 hlen=2 plen=79
:public key packet:
        version 4, algo 19, created 0, expires 0
        pkey[0]: 052B8104000A secp256k1 (1.3.132.0.10)
        pkey[1]: 4615813D2D31329D51E5A8E7C8EAA65637E9AD5DE00EA3FA65B2F1325ACED0A527B6D28E1818E1F3D797D37F3C7C8256FF5F711756255A25F422224540966ED708
        keyid: F50C012FB632C4B9
# off=81 ctb=b4 tag=13 hlen=2 plen=35
:user ID packet: "Drew Carey Buglione <[email protected]>"
# gpg --allow-non-selfsigned-uid --import public_key_invalid.gpg

gpg: key F50C012FB632C4B9: accepted non self-signed user ID "Drew Carey Buglione <[email protected]>"
gpg: key F50C012FB632C4B9: public key "Drew Carey Buglione <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1

For reference here's the hex dumb of the key in question:

# xxd public_key_invalid.gpg

00000000: 984f 0400 0000 0013 052b 8104 000a 0207  .O.......+......
00000010: 4615 813d 2d31 329d 51e5 a8e7 c8ea a656  F..=-12.Q......V
00000020: 37e9 ad5d e00e a3fa 65b2 f132 5ace d0a5  7..]....e..2Z...
00000030: 27b6 d28e 1818 e1f3 d797 d37f 3c7c 8256  '...........<|.V
00000040: ff5f 7117 5625 5a25 f422 2245 4096 6ed7  ._q.V%Z%.""[email protected].
00000050: 08b4 2344 7265 7720 4361 7265 7920 4275  ..#Drew Carey Bu
00000060: 676c 696f 6e65 203c 6472 6577 4064 7265  glione <drew@dre
00000070: 7762 2e75 673e                           wb.ug>

Is this a secp256k1 public key with an unconventional format? If not, does GPG accepts invalid public keys?


Appendix:

The following example is a secp256k1 public key that looks valid. As you can see in pkey[1] the public key starts with 04 and has 65 bytes length that matches the SEC-01 standard.


# gpg --list-packets --verbose public_key.gpg

# off=0 ctb=98 tag=6 hlen=2 plen=79
:public key packet:
        version 4, algo 19, created 1693583261, expires 0
        pkey[0]: 052B8104000A secp256k1 (1.3.132.0.10)
        pkey[1]: 04ED98F82674A7E4BE4460D69EF7096413B9C183D150A8994C52732E739F2952926B8AD543EC8CC2AA20D5E7B807B969111CD7E04396FA55AAB5181ACA6D046BE8
        keyid: F55B054856F2AAEB
# off=81 ctb=b4 tag=13 hlen=2 plen=29
:user ID packet: "example <[email protected]>"

Appendix 2:

Based on @mti2935 suggestion I tried to gpg --encrypt with the invalid public key as the recipient and GPG throws an error at this point. I would expect to get the error when importing the invalid key as it could lead to many bugs or security issues but that's besides the point of the initial question. Also, I'm not sure if it's intentional or it's worth reporting to the GPG team.

# gpg --encrypt -r F50C012FB632C4B9 -u CD6D9D53093AAEEE notes.md     

gpg: F50C012FB632C4B9: skipped: Unusable public key
gpg: notes.md: encryption failed: Unusable public key

In contrast, using a valid public key key gives the following output:

# gpg --encrypt -r F55B054856F2AAEB -u CD6D9D53093AAEEE notes.md

gpg: EAD5F63C8275D1B0: There is no assurance this key belongs to the named user

sub  secp256k1/EAD5F63C8275D1B0 2023-09-01 example <[email protected]>
 Primary key fingerprint: 0299 7081 F6CC E0FE 2E52  F9E1 F55B 0548 56F2 AAEB
      Subkey fingerprint: 374E FAA0 99AD 3C28 BBC9  9494 EAD5 F63C 8275 D1B0

...
2
  • WRT 'All other secp256k1 public keys I generated or found online start with 02 if they are compressed and 04 if they are not' - would it be possible for you to post an example of such a key, so as to have a known valid key to compare with?
    – mti2935
    Sep 7, 2023 at 14:24
  • @mti2935 Thanks for the suggestion. I added a key that matches the SEC-1 standard for more clarity. Sep 7, 2023 at 21:58

1 Answer 1

3

If an EC public key is valid, then the x,y values of the EC public key point should lie on the EC curve, which is defined by the equation:

y^2 = x^3 + ax + b

For secp256k1, a=0 and b=7.

If a point lies on the EC curve, then the following equation will be satisfied when plugging in the x,y values of the point:

(y^2 - x^3 - ax - b) % p == 0

For secp256k1, p=fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f.

For the known valid secp256k1 public key that you posted, we can in fact confirm that the point lies on the curve using the short python script below. After removing the 04 prefix from the public key, the next 32 bytes are assigned to x, and the remaining 32 bytes to y:

#secp256k1
p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
a=0
b=7

x=0xED98F82674A7E4BE4460D69EF7096413B9C183D150A8994C52732E739F295292
y=0x6B8AD543EC8CC2AA20D5E7B807B969111CD7E04396FA55AAB5181ACA6D046BE8

if( (y * y - x * x * x - a * x - b) % p == 0 ):
    print('point is on curve')
else:
    print('point is not on curve')

As expected, the script produces point is on curve when run.

However, doing the same with the public key value from your public_key_invalid.gpg file produces point is not on curve. So, it does in fact seem that the public key in this file is invalid.

Having said that, it's surprising that gpg would import this public key, without throwing an error. What happens if you try to encrypt a file using this public key?

1
  • Thanks for sharing the simple python script. Indeed, GPG fails to encrypt to the recipient with the invalid key. Added a 2nd appendix for a bit more info. Sep 11, 2023 at 9:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .