Shruggie
Shruggie

Reputation: 938

Create EC private key from input keying material in NodeJS

I'd like to derive an elliptic curve private key from input keying material (a master key). Is this possible?

Attempts

Node's crypto function, crypto.generateKeyPair does not accept input keying material, and crypto.createPrivateKey only converts a .pem to Node's native KeyObject.

I also can't find a way to do this in OpenSSL using ecparam. The -rand flag seems promising but isn't widely available (it's not on my machine).

Why / Details

I need to create a number of secrets and want have all of them derived from a single master key. This is analogous to HKDF.

I'm using the keys for ECDSA with curve P-384 (secp384r1).

Upvotes: 1

Views: 2630

Answers (1)

dave_thompson_085
dave_thompson_085

Reputation: 39000

I'm surprised you think ecparam -rand file -genkey ... is rare; it's in every upstream version back at least to 0.9.8 in 2005, and it's not one of the things that can be omitted by a build (configure) option, so your machine must have one weird version. But it doesn't matter because -rand doesn't do what you want; it adds the file data to the RNG 'pool' but does not replace it, so it doesn't give you deterministic key generation.

As Woodstock commented, for all practical purposes a raw P-384 private key is just 384 bits from any good random generator, or deterministically from any uniform random function. Technically you should exclude zero and values greater than or equal to the (sub)group order n, but those exclusions are so small relative to 2^384 that there is essentially no chance a good random choice will hit them during the lifetime of the Earth, and perhaps of the universe. You might want to look at how Bitcoin 'hierarchical deterministic' key derivation aka BIP 32 works, although of course that does 256-bit keys for secp256k1.

That leaves you the problem of converting the raw key to a form usable by nodejs crypto (which is a fairly thin wrapping of openssl library) and/or openssl commandline. To do this follow the principles of How to convert an ECDSA key to PEM format which is in turn based on https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem except use the OID and size(s) for P-384 instead of secp256k1. Specifically, concatenate

  • the 7 bytes represented in hex by 303e0201010430
  • the 48 bytes (384 bits) of the raw private key
  • the 9 bytes represented in hex by a00706052b81040022 (for P-384 aka secp384r1)

Depending on your language(s) or tool(s) you might handle these values directly, or concatenate the hex representations and then convert to binary. The result is the 'DER' (binary) form of the algorithm-specific (SEC1) private key (only), which can be read by nodejs 11 or 12 crypto.createPrivateKey( {key:(data), format:'der', type:'sec1'} ) and also by commandline openssl ec -inform der.

If you prefer textlike things (e.g. for cut&paste), convert the DER above to base64, break into lines of 64 chars (other than the last), and add lines -----BEGIN EC PRIVATE KEY----- before and -----END EC PRIVATE KEY------ after. This is PEM format and can be read by createPrivateKey without any other options, and by openssl ec without any option.

Upvotes: 4

Related Questions