Problems with deriving EC public key from private

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Problems with deriving EC public key from private

Mike Blaguszewski
Some code of mine reads a NIST P256 private key from bytes and derives the public key from it, and this derived public key is incorrect about 0.4% of the time. I’ve attached a sample program that does the following.

1. Generate a key-pair of type NID_X9_62_prime256v1
2. Write the public and private components to memory
3. Read the private key back from memory, derive the public key, and write that back out.
4. Compare this “round-tripped” public key to the public key generated in step 2.

The public key from step 2 almost always matches the public key from step 3, but about 0.4% of the time they will differ. (The sample program runs a loop to determine this.) Further experiments suggest it’s the private_key_from_binary() function that is the problem, where I derive the public key using EC_POINT_mul(). The sample program omits error checking, but in the production code no errors are reported.

Does anyone see a flaw in my logic, especially in how I’m deriving the public key from the private key? Also let me know if this would be better submitted as a GitHub issue, or even if it needs to be handled as a paid support request.

Thanks,
Mike


--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users

ec_key_example.cxx (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Problems with deriving EC public key from private

Billy Brumley
On Tue, Dec 18, 2018 at 12:07 AM Mike Blaguszewski <[hidden email]> wrote:

>
> Some code of mine reads a NIST P256 private key from bytes and derives the public key from it, and this derived public key is incorrect about 0.4% of the time. I’ve attached a sample program that does the following.
>
> 1. Generate a key-pair of type NID_X9_62_prime256v1
> 2. Write the public and private components to memory
> 3. Read the private key back from memory, derive the public key, and write that back out.
> 4. Compare this “round-tripped” public key to the public key generated in step 2.
>
> The public key from step 2 almost always matches the public key from step 3, but about 0.4% of the time they will differ. (The sample program runs a loop to determine this.) Further experiments suggest it’s the private_key_from_binary() function that is the problem, where I derive the public key using EC_POINT_mul(). The sample program omits error checking, but in the production code no errors are reported.
>
> Does anyone see a flaw in my logic, especially in how I’m deriving the public key from the private key? Also let me know if this would be better submitted as a GitHub issue, or even if it needs to be handled as a paid support request.

The sample code just segfaults for me in the first iteration, before
really generating a key, so it's hard to test:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a7e3e0 in pkey_set_type (pkey=0x380, type=408, str=0x0,
len=-1) at crypto/evp/p_lib.c:181
(gdb) bt
#0  0x00007ffff7a7e3e0 in pkey_set_type (pkey=0x380, type=408,
str=0x0, len=-1) at crypto/evp/p_lib.c:181
#1  0x00007ffff7a7e546 in EVP_PKEY_set_type (pkey=0x380, type=408) at
crypto/evp/p_lib.c:221
#2  0x00007ffff7a7e663 in EVP_PKEY_assign (pkey=0x380, type=408,
key=0x5555557587c0) at crypto/evp/p_lib.c:249
#3  0x00007ffff7a248fb in pkey_ec_keygen (ctx=0x555555758760,
pkey=0x380) at crypto/ec/ec_pmeth.c:416
#4  0x00007ffff7a80912 in EVP_PKEY_keygen (ctx=0x555555758760,
ppkey=0x7fffffffdd18) at crypto/evp/pmeth_gn.c:107
#5  0x0000555555555046 in generate_ec_key () at foo.c:18
#6  0x0000555555555256 in main () at foo.c:73

But 0.4% is suspiciously close to 1/256, so I'm willing to bet your
problem surrounds your size assumptions in various functions. Check
the manpage of e.g. EC_POINT_point2oct and grep for usage in the
library, but the idea is to pass NULL first, then malloc, then pass
that pointer. BN_bn2bin is different. Probably the size won't be fixed
(e.g., there is a 1/256 chance you'll have one byte less, i.e. leading
zero).

So all the static 32 and 33 byte assumptions aren't holding.

Also BN_bn2bin and EC_KEY_oct2priv are not inverses of each other
IIRC. (The former is raw bytes, latter ASN1 encoding.)

BBB
--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
Reply | Threaded
Open this post in threaded view
|

Re: Problems with deriving EC public key from private

Mike Blaguszewski
On Dec 17, 2018, at 11:42 PM, Billy Brumley <[hidden email]> wrote:
>
> But 0.4% is suspiciously close to 1/256, so I'm willing to bet your
> problem surrounds your size assumptions in various functions. Check
> the manpage of e.g. EC_POINT_point2oct and grep for usage in the
> library, but the idea is to pass NULL first, then malloc, then pass
> that pointer. BN_bn2bin is different. Probably the size won't be fixed
> (e.g., there is a 1/256 chance you'll have one byte less, i.e. leading
> zero).

Thanks so much! That was exactly it. Switching from BN_bn2bin() to EC_KEY_priv2oct() resolves the problem. (As does BN_bn2binpad(), but using the more standard binary format seems preferable.) I will also look into pre-flighting the calls with a NULL buffer.

Mike

P.S. not sure why it crashed for you, but I’d guess some combination of different OpenSSL versions and an error return being ignored by the sample code. I appreciate you taking a look despite that.
--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users