246 lines
6.1 KiB
Markdown
246 lines
6.1 KiB
Markdown
[Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js)
|
|
=========
|
|
|
|
Sponsored by [Root](https://therootcompany.com).
|
|
Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
|
|
and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
|
|
|
|
| < 600 lines of code | 3kb gzipped | 10kb minified | 17kb with comments |
|
|
|
|
ECDSA (elliptic curve) tools. Lightweight. Zero Dependencies. Universal compatibility.
|
|
|
|
* [x] Fast and Easy EC Key Generation
|
|
* [x] PEM-to-JWK
|
|
* [x] JWK-to-PEM
|
|
* [x] SSH "pub" format
|
|
* [x] CLI
|
|
* [ ] RSA
|
|
* **Need RSA tools?** Check out [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js)
|
|
|
|
## Install
|
|
|
|
For node.js:
|
|
|
|
```bash
|
|
npm install --save eckles
|
|
```
|
|
|
|
CLI:
|
|
|
|
```bash
|
|
npm install -g eckles
|
|
```
|
|
|
|
## Generate EC (ECDSA/ECDH) Key
|
|
|
|
Achieves the *fastest possible key generation* using node's native EC bindings to OpenSSL,
|
|
then converts to JWK for ease-of-use.
|
|
|
|
```js
|
|
Eckles.generate({ format: 'jwk' }).then(function (keypair) {
|
|
console.log(keypair.private);
|
|
console.log(keypair.public);
|
|
});
|
|
```
|
|
|
|
**options**
|
|
|
|
* `format` defaults to `'jwk'`
|
|
* `'sec1'` (traditional)
|
|
* `'pkcs8'`
|
|
* `'ssh'`
|
|
* `encoding` defaults to `'json'`
|
|
* `'pem'` (type + DER.toString('base64'))
|
|
* `'der'`
|
|
|
|
**advanced options**
|
|
|
|
* `namedCurve` defaults to `'P-256'`
|
|
* `P-384` is also supported
|
|
* larger keys have not been implemented
|
|
* A) because they're a senseless waste
|
|
* B) they have similar, but slightly different formats
|
|
|
|
#### Generate EC Key CLI
|
|
|
|
```bash
|
|
# Generate a key in each format
|
|
# eckles [format] [curve|encoding]
|
|
eckles jwk
|
|
eckles sec1 pem
|
|
eckles pkcs8 der
|
|
eckles ssh P-256
|
|
```
|
|
|
|
## PEM-to-JWK
|
|
|
|
* [x] SEC1/X9.62, PKCS#8, SPKI/PKIX
|
|
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
|
|
* [x] SSH (RFC4716), (RFC 4716/SSH2)
|
|
|
|
```js
|
|
var Eckles = require('eckles');
|
|
var pem = require('fs')
|
|
.readFileSync('./node_modles/eckles/fixtures/privkey-ec-p256.sec1.pem', 'ascii');
|
|
|
|
Eckles.import({ pem: pem }).then(function (jwk) {
|
|
console.log(jwk);
|
|
});
|
|
```
|
|
|
|
```js
|
|
{
|
|
"kty": "EC",
|
|
"crv": "P-256",
|
|
"d": "iYydo27aNGO9DBUWeGEPD8oNi1LZDqfxPmQlieLBjVQ",
|
|
"x": "IT1SWLxsacPiE5Z16jkopAn8_-85rMjgyCokrnjDft4",
|
|
"y": "mP2JwOAOdMmXuwpxbKng3KZz27mz-nKWIlXJ3rzSGMo"
|
|
}
|
|
```
|
|
|
|
#### EC PEM to JWK CLI
|
|
|
|
```bash
|
|
# Convert SEC1, PKCS8, SPKI, SSH to JWK
|
|
# eckles [keyfile]
|
|
eckles node_modules/eckles/fixtures/privkey-ec-p256.sec1.pem
|
|
eckles node_modules/eckles/fixtures/privkey-ec-p384.pkcs8.pem
|
|
eckles node_modules/eckles/fixtures/pub-ec-p256.spki.pem
|
|
eckles node_modules/eckles/fixtures/pub-ec-p384.ssh.pub
|
|
```
|
|
|
|
## JWK-to-PEM
|
|
|
|
* [x] SEC1/X9.62, PKCS#8, SPKI/PKIX
|
|
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
|
|
* [x] SSH (RFC4716), (RFC 4716/SSH2)
|
|
|
|
```js
|
|
var Eckles = require('eckles');
|
|
var jwk = require('eckles/fixtures/privkey-ec-p256.jwk.json');
|
|
|
|
Eckles.export({ jwk: jwk }).then(function (pem) {
|
|
// PEM in SEC1 (x9.62) format
|
|
console.log(pem);
|
|
});
|
|
```
|
|
|
|
```
|
|
-----BEGIN EC PRIVATE KEY-----
|
|
MHcCAQEEIImMnaNu2jRjvQwVFnhhDw/KDYtS2Q6n8T5kJYniwY1UoAoGCCqGSM49
|
|
AwEHoUQDQgAEIT1SWLxsacPiE5Z16jkopAn8/+85rMjgyCokrnjDft6Y/YnA4A50
|
|
yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg==
|
|
-----END EC PRIVATE KEY-----
|
|
```
|
|
|
|
#### EC PEM to JWK CLI
|
|
|
|
```bash
|
|
# Convert JWK to SEC1, PKCS8, SPKI, SSH
|
|
# eckles [keyfile] [format]
|
|
eckles node_modules/eckles/fixtures/privkey-ec-p256.jwk.json sec1
|
|
eckles node_modules/eckles/fixtures/privkey-ec-p384.jwk.json pkcs8
|
|
eckles node_modules/eckles/fixtures/pub-ec-p256.jwk.json spki
|
|
eckles node_modules/eckles/fixtures/pub-ec-p384.jwk.json ssh
|
|
```
|
|
|
|
### Advanced Options
|
|
|
|
`format: 'pkcs8'`:
|
|
|
|
The default output format is `sec1`/`x9.62` (EC-specific format) is used for private keys.
|
|
Use `format: 'pkcs8'` to output in PKCS#8 format instead.
|
|
|
|
```js
|
|
Eckles.export({ jwk: jwk, format: 'pkcs8' }).then(function (pem) {
|
|
// PEM in PKCS#8 format
|
|
console.log(pem);
|
|
});
|
|
```
|
|
|
|
```
|
|
-----BEGIN PRIVATE KEY-----
|
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiYydo27aNGO9DBUW
|
|
eGEPD8oNi1LZDqfxPmQlieLBjVShRANCAAQhPVJYvGxpw+ITlnXqOSikCfz/7zms
|
|
yODIKiSueMN+3pj9icDgDnTJl7sKcWyp4Nymc9u5s/pyliJVyd680hjK
|
|
-----END PRIVATE KEY-----
|
|
```
|
|
|
|
`format: 'ssh'`:
|
|
|
|
Although SSH uses SEC1 for private keys, it uses ts own special non-ASN1 format
|
|
(affectionately known as rfc4716) for public keys. I got curious and then decided
|
|
to add this format as well.
|
|
|
|
To get the same format as you
|
|
would get with `ssh-keygen`, pass `ssh` as the format option:
|
|
|
|
```js
|
|
Eckles.export({ jwk: jwk, format: 'ssh' }).then(function (pub) {
|
|
// Special SSH2 Public Key format (RFC 4716)
|
|
console.log(pub);
|
|
});
|
|
```
|
|
|
|
```
|
|
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCE9Uli8bGnD4hOWdeo5KKQJ/P/vOazI4MgqJK54w37emP2JwOAOdMmXuwpxbKng3KZz27mz+nKWIlXJ3rzSGMo= P-256@localhost
|
|
```
|
|
|
|
`public: 'true'`:
|
|
|
|
If a private key is used as input, a private key will be output.
|
|
|
|
If you'd like to output a public key instead you can pass `public: true` or `format: 'spki'`.
|
|
|
|
```js
|
|
Eckles.export({ jwk: jwk, public: true }).then(function (pem) {
|
|
// PEM in SPKI/PKIX format
|
|
console.log(pem);
|
|
});
|
|
```
|
|
|
|
```
|
|
-----BEGIN PUBLIC KEY-----
|
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIT1SWLxsacPiE5Z16jkopAn8/+85
|
|
rMjgyCokrnjDft6Y/YnA4A50yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg==
|
|
-----END PUBLIC KEY-----
|
|
```
|
|
|
|
Testing
|
|
-------
|
|
|
|
All cases are tested in `test.sh`.
|
|
|
|
You can compare these keys to the ones that you get from OpenSSL, ssh-keygen, and WebCrypto:
|
|
|
|
```bash
|
|
# Generate EC P-256 Keypair
|
|
openssl ecparam -genkey -name prime256v1 -noout -out ./privkey-ec-p256.sec1.pem
|
|
|
|
# Export Public-only EC Key (as SPKI)
|
|
openssl ec -in ./privkey-ec-p256.sec1.pem -pubout -out ./pub-ec-p256.spki.pem
|
|
|
|
# Convert SEC1 (traditional) EC Keypair to PKCS8 format
|
|
openssl pkcs8 -topk8 -nocrypt -in ./privkey-ec-p256.sec1.pem -out ./privkey-ec-p256.pkcs8.pem
|
|
|
|
# Convert EC public key to SSH format
|
|
ssh-keygen -f ./pub-ec-p256.spki.pem -i -mPKCS8 > ./pub-ec-p256.ssh.pub
|
|
```
|
|
|
|
Goals of this project
|
|
-----
|
|
|
|
* Zero Dependencies
|
|
* Focused support for P-256 and P-384, which are already universally supported.
|
|
* Convert both ways
|
|
* Browser support as well (TODO)
|
|
* OpenSSL, ssh-keygen, and WebCrypto compatibility
|
|
|
|
Legal
|
|
-----
|
|
|
|
[Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js) |
|
|
MPL-2.0 |
|
|
[Terms of Use](https://therootcompany.com/legal/#terms) |
|
|
[Privacy Policy](https://therootcompany.com/legal/#privacy)
|