简体   繁体   中英

Set an EVP_PKEY from EC raw points, PEM or DER in both OpenSSL 1.1.1 and 3.0.x

I want to write some code that works against OpenSSL 1.1.1 and 3.0.x and future versions.

The code should set an EVP_PKEY to a particular EC key pair from either the points, DER or PEM. I don't really care which, because I know how to convert between them.

EVP_PKEY_fromdata() seems like the way to do it in 3.0.x, but it is not supported in 1.1.1.

You can't create an ECC 'keypair' from 'points' (in OpenSSL or anywhere). You can create a public key from one point plus the 'curve' (or more exactly parameter-set); for the Bernstein et al XDH schemes you use one coordinate (X) of the point instead of the whole point. To create a private key or keypair you must have the private key value, a scalar which is not a point or even a coordinate, and the 'curve'. (In proper mathematics an elliptic curve of the type used in crypto consists of an underlying finite field aka Galois field, with order either a sufficiently large prime or a sufficiently large power of two, plus a two-variable equation over that field in a standard form such as Weierstrass or Edwards which defines a set of points each having X,Y coordinates in the underlying field, plus a binary operation conventionally notated as addition over those points plus a special value called the point at infinity used as the additive identity, forming a finite cyclic group. However, to use such a curve in crypto we must also have a defined 'base' or generator point (or for XDH an X-coordinate defining a point together with its inverse), plus the order of the (sub)group generated by that base point (etc) under the curve operation, and its 'cofactor' relative to the full-group order; in some cases we also have information about how the curve was selected, and in most cases we also have associa ted identifier(s). Nonpedantic crypto people now generally use 'curve' to mean the combination of these. Although in principle applications and systems could define their own parameters=curves for ECC, as many did and do for non-elliptic DSA and DH, practically everyone uses curves specified by a standards organization which can be accessed by an identifier, such as 'P-256' and 'P-384' for the most commonly used curves identified by NIST (so far -- SP800-186 now in draft plans to add 25519 and 448, which are becoming about as common) and recommended by NSA, rather than specifying the extensive details of the underlying field, equation, basepoint, etc.)

For 'traditional' EC as defined by X9 using Weierstrass-form curves, OpenSSL supports several ASN.1 (external) representations for private keys and one for public keys, each in either 'DER' (binary) or PEM-style. For the Bernstein curves it supports one or two (depending how you count) private key and one public key, ditto. Specifically

  • for public key (for both ECC and other algorithms) it uses the SubjectPublicKeyInfo structure defined in X.509 and repeated in PKIX; for X9-type curves this contains data defined by X9 and repeated in RFC3279 2.3.5 updated and modified by RFC5480 2 while for Bernstein curves will add later .

    OpenSSL calls this format PUBKEY. It can be read into EVP_PKEY by d2i_PUBKEY[_bio|fp] for DER and PEM_read[_bio]_PUBKEY for PEM. It can also be read into an algorithm-specific EC_KEY by similar EC_PUBKEY routines and that EC_KEY then used to build EVP_PKEY , but why bother?

  • for private key for X9-style only OpenSSL supports the algorithm-specific format defined in https://www.secg.org SEC1 appendix C and repeated in RFC5915 read from DER by d2i_ECPrivateKey[] into EC_KEY and used to build EVP_PKEY similar to the above.

  • for private key for all curves OpenSSL supports the generic PKCS8 format(s) defined in RFC5208 which includes an unencrypted and a password-encrypted version, read from DER by respectively d2i_PrivateKey[] and d2i_PKCS8PrivateKey{} .

  • for private key in PEM there is only one group of routines PEM_read[]_PrivateKey which can handle both unencrypted and encrypted PKCS8 (distinguished by PEM label) and for X9-style unencrypted and PEM-encrypted SEC1 (distinguished by PEM label and headers).

If you don't have (and don't want to convert to or construct) one of these ASN.1 representations, the alternative is to create your key(s) 'by hand'.

For X9-style, this uses the EC_GROUP and EC_KEY internal (ie C-API) structures which respectively describe a curve as above and contain a public-key or key-pair on such a curve. If you are using a standard curve known to OpenSSL, you can get the EC_GROUP by calling EC_GROUP_new_by_curve_name and use it to build an EC_KEY , or simply call EC_KEY_new_by_curve_name . Note the 'name' here is not a true name like 'secp256k1' but OpenSSL's 'nid' -- an OpenSSL-assigned int that encodes a name (or if applicable both a full name and a short/abbreviated name) and corresponding X.509 object identifier (OID); see OBJ_txt2nid and related routines. If you want a custom/explicit curve it's quite a bit more complicated, and I'm not going into that unless you specify exactly what information you (will) have. Then call EC_KEY_set_{private,public}_key as applicable, for public key after parsing or converting the point data if necessary. Finally use the EC_KEY to build EVP_PKEY .

For Bernstein curves, create the EVP_PKEY directly with EVP_PKEY_new_raw_{private,public}_key by specifying the scheme; XDH and EdDSA and 25519 and 448 are treated as separate algorithms in OpenSSL, although the XDH and EdDSA forms of each curve are mathematically equivalent, because they are represented and implemented differently.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM