Compare commits

...

13 Commits
v0.9.0 ... main

23 changed files with 243 additions and 168 deletions

6
.jshintrc Normal file
View File

@ -0,0 +1,6 @@
{
"esversion": 11,
"node": true,
"unused": true,
"curly": true
}

8
.prettierrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"bracketSpacing": true,
"printWidth": 80,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "none",
"useTabs": true
}

View File

@ -1,4 +1,4 @@
# @root/keypairs
# [@root/keypairs](https://git.rootprojects.org/root/keypairs.js)
Lightweight JavaScript RSA and ECDSA utils that work on Windows, Mac, and Linux
using modern node.js APIs (no need for C compiler).
@ -20,6 +20,8 @@ and [Rasha.js (RSA)](https://git.coolaj86.com/coolaj86/rasha.js/).
- [ ] Auth0
- [ ] CLI
- See [keypairs-cli](https://npmjs.com/packages/keypairs-cli/)
- [x] Node
- [x] Browsers (Webpack >=5)
<!--
@ -86,6 +88,72 @@ return Keypairs.signJwt({
By default ECDSA keys will be used since they've had native support in node
_much_ longer than RSA has, and they're smaller, and faster to generate.
## Webpack 5+ (for Browsers)
This package includes native browser versions of all special functions.
Since Webpack 5 now fully supports vanilla JavaScript and exclusive browser builds out-of-the-box,
it's pretty easy to create a minimal config to use Keypairs in your browser projects:
`webpack.config.js`:
```js
'use strict';
var path = require('path');
module.exports = {
entry: './main.js',
mode: 'development',
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 3001
},
output: {
publicPath: 'http://localhost:3001/'
},
module: {
rules: [{}]
},
plugins: []
};
```
`main.js`:
```js
'use strict';
var Keypairs = require('./keypairs.js');
Keypairs.generate().then(function (pair) {
console.log(pair.private);
console.log(pair.public);
});
```
`index.html`:
```html
<!DOCTYPE html>
<html>
<body>
<script src="./dist/main.js"></script>
</body>
</html>
```
```bash
npm install --save-dev webpack@5
# Or, if webpack 5 is still in beta: npm install --save-dev webpack@next
npm install --save-dev webpack-cli
npx webpack --mode=production
ls dist/main.js
```
## API Overview
- generate (JWK)

View File

@ -107,7 +107,7 @@ Keypairs.generate = function(opts) {
} else if (/^RSA$/i.test(opts.kty)) {
p = Rasha.generate(opts);
} else {
return Promise.Reject(
return Promise.reject(
new Error(
"'" +
opts.kty +
@ -218,7 +218,7 @@ Keypairs.signJwt = function(opts) {
var claims = JSON.parse(JSON.stringify(opts.claims || {}));
header.typ = 'JWT';
if (!header.kid && false !== header.kid) {
if (!header.kid && !header.jwk && false !== header.kid) {
header.kid = thumb;
}
if (!header.alg && opts.alg) {
@ -294,19 +294,19 @@ Keypairs.signJws = function(opts) {
if (!protect.alg) {
protect.alg = alg();
}
// There's a particular request where ACME / Let's Encrypt explicitly doesn't use a kid
// There should be a kid unless it's `false` or there's a `jwk` (a self-signed JWS)
if (!protect.kid) {
if (false === protect.kid) {
protect.kid = undefined;
} else if (!protect.kid) {
} else if (!protect.jwk) {
protect.kid = thumb;
}
}
protectedHeader = JSON.stringify(protect);
}
// Not sure how to handle the empty case since ACME POST-as-GET must be empty
//if (!payload) {
// throw new Error("opts.payload should be JSON, string, or ArrayBuffer (it may be empty, but that must be explicit)");
//}
// Trying to detect if it's a plain object (not Buffer, ArrayBuffer, Array, Uint8Array, etc)
if (
payload &&

View File

@ -9,5 +9,7 @@ sha2.sum = function(alg, str) {
data = encoder.encode(str);
}
var sha = 'SHA-' + String(alg).replace(/^sha-?/i, '');
return window.crypto.subtle.digest(sha, data);
return window.crypto.subtle.digest(sha, data).then(function (buf) {
return new Uint8Array(buf);
});
};

View File

@ -13,10 +13,7 @@ module.exports = function(bitlen, exp) {
}
var keypair = ursa.generatePrivateKey(bitlen, exp);
var result = {
privateKeyPem: keypair
.toPrivatePem()
.toString('ascii')
.trim()
privateKeyPem: keypair.toPrivatePem().toString('ascii').trim()
};
return result;
};

View File

@ -10,10 +10,7 @@ Keypairs._sign = function(opts, payload) {
// node specifies RSA-SHAxxx even when it's actually ecdsa (it's all encoded x509 shasums anyway)
// TODO opts.alg = (protect||header).alg
var nodeAlg = 'SHA' + Keypairs._getBits(opts);
var binsig = crypto
.createSign(nodeAlg)
.update(payload)
.sign(pem);
var binsig = crypto.createSign(nodeAlg).update(payload).sign(pem);
if ('EC' === opts.jwk.kty && !/x509|asn1/i.test(opts.format)) {
// ECDSA JWT signatures differ from "normal" ECDSA signatures

View File

@ -9,9 +9,6 @@ sha2.sum = function(alg, str) {
var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
// utf8 is the default for strings
var buf = Buffer.from(str);
return crypto
.createHash(sha)
.update(buf)
.digest();
return crypto.createHash(sha).update(buf).digest();
});
};

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "@root/keypairs",
"version": "0.9.0",
"version": "0.10.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@root/keypairs",
"version": "0.9.0",
"version": "0.10.2",
"description": "Lightweight, Zero-Dependency RSA and EC/ECDSA crypto for Node.js and Browsers",
"main": "keypairs.js",
"browser": {
@ -20,7 +20,7 @@
],
"repository": {
"type": "git",
"url": "https://git.rootprojects.org/root/csr.js.git"
"url": "https://github.com/therootcompany/keypairs.js.git"
},
"keywords": [
"ASN.1",

View File

@ -89,14 +89,14 @@ Keypairs.parseOrGenerate({ key: null })
return true;
}
),
Keypairs.parse({ key: JSON.stringify(pair.private) }).then(function(
pair
) {
Keypairs.parse({ key: JSON.stringify(pair.private) }).then(
function (pair) {
if (!pair.private || !pair.public) {
throw new Error('missing key pairs (stringified jwt)');
}
return true;
}),
}
),
Keypairs.parse({
key: JSON.stringify(pair.private),
public: true