UNPKG

ec-key-patch

Version:

Wrapper around an Elliptic Curve private or public keys

295 lines (208 loc) 10.2 kB
Elliptic Curve Keys =================== This project defines a wrapper for Elliptic Curve (EC) private and public keys. * [Curves](#curves); * [Basic Construction](#basic-construction) * [Randomly generated keys](#randomly-generated-keys) * [Instantiating from encoded keys](#instantiating-from-encoded-keys) * [Instantiating with objects](#instantiating-with-objects) * [ECKey properties](#eckey-properties) * [ECKey functions](#eckey-functions) * [`asPublicECKey()`](#-aspubliceckey-) * [`computeSecret(otherKey)`](#-computesecret-otherkey-) * [`createECDH()`](#-createecdh-) * [`createSign(hash)`](#-createsign-hash-) * [`createVerify(hash)`](#-createverify-hash-) * [`toBuffer(format)`](#-tobuffer-format-) * [`toString(format)`](#-tostring-format-) * [`toJSON()`](#-tojson-) * [MIT License](LICENSE.md) Curves ------ This wrapper supports onl the three main curves listed below: | OpenSSL Curve Name | RFC-7518 (6.2.1.1) | ASN.1 OID | | ------------------ | ----------------------- | ------------------- | | `prime256v1` | `P-256` | 1.2.840.10045.3.1.7 | | `secp384k1` | `P-256K` _non standard_ | 1.3.132.0.10 | | `secp384r1` | `P-384` | 1.3.132.0.34 | | `secp521r1` | `P-521` | 1.3.132.0.35 | Both the OpenSSL names and RFC-7518 (JWA/JWK) names can be used as parameters to the methods in the `ECKey` class. Please be aware that _NodeJS_ (and _OpenSSL_) support a large number of curves (see `openssl ecparam -list_curves` for a full list), but for brevity this implementation restricts to the three mentioned above. > *PLEASE NOTE:* The `P-256K` curve name (`crv` parameter) used when serializing > a key using the `secp384k1` curve is not standard, and *NOT* interoperable > with other systems. > > See the [IANA](https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve) > registry for all known (and interoperable) curve names. > > The `P-256K` name used might change at _ANY_ time. Basic construction ------------------ To use, start importing the main `ECKey` class: ```javascript const ECKey = require('ec-key'); ``` #### Randomly generated keys To create a random `ECKey` instance simply call the `createECKey` static method, optionally specifying a curve name (defaults to `prime256v1`): ```javascript // Create a new (random) ECKey instance using the secp521r1 curve var randomKey = ECKey.createECKey('P-521'); ``` #### Instantiating from encoded keys To import an existing private or public key, simply invoke the constructor with a `String` or a `Buffer` and the format in which the key is encoded: ```javascript // Create a new ECKey instance from a base-64 spki string var key = new ECKey('MFkwEw ... 3w06qg', 'spki'); ``` For `Buffer`s and _base64-encoded_ `String`s the constructor supports both the `pkcs8` (or `rfc5208`) and `spki` (or `rfc5280`) formats. Additionally, the `pem` format is supported for _unencoded_ `String`s and `Buffer`s: ```javascript // Load up a PEM file and wrap it into a var pem = fs.readFileSync('./key.pem'); var key = new ECKey(pem, 'pem'); ``` #### Instantiating with objects Instances of the `ECKey` class can also be created from very simple object. For example JWKs can be used directly, and whereas in the example below the `crv`, `x` and `y` values will be considered, `kty` and `kid` will be ignored. ```javascript /// Simply create from a JWK object var key = new ECKey({ "kty":"EC", "crv":"P-256", "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU", "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0", "kid":"Public key used in JWS spec Appendix A.3 example" }) ``` The following values are recognized: * **`curve`** or **`crv`**: the curve type for this key, identified either by its _OpenSSL_ or its _RFC-7518 (JWA/JWK)_ name. With regards to coordinates: * **`d`**: the private _d_ coordinate for the elliptic curve point, either as a `Buffer`, or a _base64-encoded_ `String` of the coordinate's big endian representation * **`x`**: the public _x_ coordinate for the elliptic curve point, either as a `Buffer`, or a _base64-encoded_ `String` of the coordinate's big endian representation * **`y`**: the public _y_ coordinate for the elliptic curve point, either as a `Buffer`, or a _base64-encoded_ `String` of the coordinate's big endian representation And also: * **`publicKey`**: the _uncompressed_ and _prefixed_ (0x04) concatenation of the _x_ and _y_ public coordinates' big endian representation, as described in [SEC-1 ECC](http://www.secg.org/sec1-v2.pdf) section 2.3.3 * **`privateKey`**: the private _d_ coordinate for the elliptic curve point, either as a `Buffer`, or a _base64-encoded_ `String` of the coordinate's big endian representation ECKey properties ---------------- The following _enumerable_ properties are available for instances of `ECKey`: * **`curve`**: the EC key curve name in _OpenSSL_ format (e.g. `prime256v1`) * **`isPrivateECKey`**: a _boolean_ indicating whther this instance represents a _private_ or _public_ EC key. * **`x`**: the public _x_ coordinate's big endian representation for the elliptic curve point as a `Buffer` * **`y`**: the public _y_ coordinate's big endian representation for the elliptic curve point as a `Buffer` * **`d`**: the private _d_ coordinate's big endian representation for the elliptic curve point as a `Buffer` Additionally the following properties are available, but not _enumerable_: * **`jsonCurve`**: the EC key curve name in _RFC-7518_ format (e.g. `P-256`) * **`publicCodePoint`**: the _uncompressed_ and _prefixed_ (0x04) concatenation of the _x_ and _y_ public coordinates' big endian representation, as described in [SEC-1 ECC](http://www.secg.org/sec1-v2.pdf) section 2.3.3. ECKey functions --------------- #### `asPublicECKey()` Return `this` instance if this key is a _public_ key, or create a new `ECKey` instance *not* including the _private_ components of the key. #### `computeSecret(otherKey)` A simple shortcut for `createECDH().computeSecret(otherKey)` as explained below. #### `createECDH()` Create a standard Node [_ECDH_](https://nodejs.org/api/crypto.html#crypto_class_ecdh) object instance whose [`computeSecret(...)`](https://nodejs.org/api/crypto.html#crypto_ecdh_computesecret_other_public_key_input_encoding_output_encoding) function accepts also `ECKey` (as in, this class) instances. #### `createSign(hash)` Create a standard Node [_Sign_](https://nodejs.org/api/crypto.html#crypto_class_sign) object whose [`sign(...)`](https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format) function is automatically populated with this instance. * `hash`: the hashing function to use for generating the signature, normally one of `SHA256`, `SHA384` or `SHA512`. ```javascript // Create a signature of the message "the quick brown fox" with a random key var message = "the quick brown fox"; var key = ECKey.createECKey('P-384'); var signature = key.createSign('SHA384') .update(message) .sign('base64'); ``` #### `createVerify(hash)` Create a standard Node [_Verify_](https://nodejs.org/api/crypto.html#crypto_class_verify) object whose [`verify(...)`](https://nodejs.org/api/crypto.html#crypto_verifier_verify_object_signature_signature_format) function is automatically populated with this instance. * `hash`: the hashing function to use for generating the signature, normally one of `SHA256`, `SHA384` or `SHA512`. ```javascript // Verify the signature calcuated above key.createVerify('SHA384') .update(message) .verify(signature, 'base64'); ``` ### `toBuffer(format)` Encode this EC key, optionally using the specified format (defaults to `pem`). Formats supported are as follows: * **`pem`**: return a `Buffer` containing the `ascii` represtation of the OpenSSL PEM format * equivalent to `new Buffer(key.toString('pem'), 'ascii')` and provided for convenience only * **`rfc5951`**: (_private_ keys only) returns the encoding of this key as specified by [RFC-5951](https://tools.ietf.org/html/rfc5951) * **`pkcs8`** or **`rfc5208`**: (_private_ keys only) returns the PKCS8 encoding of this key as specified by [RFC-5208](https://tools.ietf.org/html/rfc5208) * **`spki`** or **`rfc5280`**: (_public_ keys only) returns the SPKI encoding of this key as specified by [RFC-5280](https://tools.ietf.org/html/rfc5280) ### `toString(format)` Encode this EC key, optionally using the specified format (defaults to `pem`). Formats supported are as follows: * **`pem`**: return the key in OpenSSL's PEM format * **`rfc5951`**: (_private_ keys only) returns the encoding of this key as specified by [RFC-5951](https://tools.ietf.org/html/rfc5951), wrapped with a header and footer as outlined in section 4 * **`pkcs8`** or **`rfc5208`**: (_private_ keys only) returns the PKCS8 encoding of this key as specified by [RFC-5208](https://tools.ietf.org/html/rfc5208) encoded in _base64_ * **`spki`** or **`rfc5280`**: (_public_ keys only) returns the SPKI encoding of this key as specified by [RFC-5280](https://tools.ietf.org/html/rfc5280) encoded in _base64_ ### `toJSON()` Formats this `ECKey` as a JSON Web Key as specified by [RFC-7517](https://tools.ietf.org/html/rfc7517). Please note that his function will also be called by the `JSON.stringify(...)` function. ```javascript // Convert a PEM to a JWK in one easy step var pem = `-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgzr+Twxehecu0VYoC XUBL1Z4h3H28gPnJ5MP0AcOixAOhRANCAAS6pMWMMndZxOPSC9ui6sUUbmeK6dIi k3ZwTmm0SE7G+tYon5C57aVek5qH4y4OipbSLfbsIQuOkt0G8Vu1KZ3u -----END PRIVATE KEY-----`; var key = new ECKey(pem, 'pem'); var jwk = JSON.stringify(key, null, 2); console.log(jwk); // This will result in the following output: // { // "kty": "EC", // "crv": "P-256", // "x": "uqTFjDJ3WcTj0gvbourFFG5niunSIpN2cE5ptEhOxvo", // "y": "1iifkLntpV6TmofjLg6KltIt9uwhC46S3QbxW7Upne4", // "d": "zr-Twxehecu0VYoCXUBL1Z4h3H28gPnJ5MP0AcOixAM" // } ```