Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for old nodejs versions (req v14) #49

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 1 addition & 11 deletions .travis.yml
@@ -1,16 +1,6 @@
language: node_js
node_js:
- 0.10
- 0.11
- 0.12
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 14
notifications:
email:
recipients:
Expand Down
81 changes: 28 additions & 53 deletions index.js
@@ -1,18 +1,23 @@
var bufferEqual = require('buffer-equal-constant-time');
var Buffer = require('safe-buffer').Buffer;
var Buffer = require('buffer').Buffer;
var crypto = require('crypto');
var formatEcdsa = require('ecdsa-sig-formatter');
Copy link
Collaborator

@panva panva Sep 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node crypto's own dsaEncoding option valued ieee-p1363 can be used for ECDSA to completely remove the ecdsa-sig-formatter dependency. This was added in nodejs/node#29292 and is available in all nodejs versions above v13.2.0 and v12.16.0.

At the same time the node crypto now offers one-shot sign and verify methods which can be used both in both a blocking and non-blocking manner.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you show a code example of how to solve it...
maybe just do a little diff suggestion and then i can just apply the changes ;)

```diff
+
-
```

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sry, i'm too lost right now. don't work much with cryptografy. will leave this fully up to you guys to solve.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really just a lift and shift from the old api to the new and for ecdsa having a dedicated signer/verifier with the dsaEncoding option.

var util = require('util');

var MSG_INVALID_ALGORITHM = '"%s" is not a valid algorithm.\n Supported algorithms are:\n "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" and "none".'
var MSG_INVALID_SECRET = 'secret must be a string or buffer';
var MSG_INVALID_VERIFIER_KEY = 'key must be a string or a buffer';
var MSG_INVALID_SECRET = 'secret must be a string or buffer or a KeyObject';
var MSG_INVALID_VERIFIER_KEY = 'key must be a string or a buffer or a KeyObject';
var MSG_INVALID_SIGNER_KEY = 'key must be a string, a buffer or an object';

var supportsKeyObjects = typeof crypto.createPublicKey === 'function';
if (supportsKeyObjects) {
MSG_INVALID_VERIFIER_KEY += ' or a KeyObject';
MSG_INVALID_SECRET += 'or a KeyObject';
/**
* @param {Uint8Array} a
* @param {Uint8Array} b
*/
function timingSafeEqual(a, b) {
if (a.length !== b.length) return false

let c = 0;
for (let i = 0, len = a.length; i < len; i++) c |= a[i] ^ b[i];
return !c;
}
jimmywarting marked this conversation as resolved.
Show resolved Hide resolved

function checkIsPublicKey(key) {
Expand All @@ -24,10 +29,6 @@ function checkIsPublicKey(key) {
return;
}

if (!supportsKeyObjects) {
throw typeError(MSG_INVALID_VERIFIER_KEY);
}

if (typeof key !== 'object') {
throw typeError(MSG_INVALID_VERIFIER_KEY);
}
Expand Down Expand Up @@ -70,10 +71,6 @@ function checkIsSecretKey(key) {
return key;
}

if (!supportsKeyObjects) {
throw typeError(MSG_INVALID_SECRET);
}

if (typeof key !== 'object') {
throw typeError(MSG_INVALID_SECRET);
}
Expand All @@ -87,31 +84,8 @@ function checkIsSecretKey(key) {
}
}

function fromBase64(base64) {
return base64
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}

function toBase64(base64url) {
base64url = base64url.toString();

var padding = 4 - base64url.length % 4;
if (padding !== 4) {
for (var i = 0; i < padding; ++i) {
base64url += '=';
}
}

return base64url
.replace(/\-/g, '+')
.replace(/_/g, '/');
}

function typeError(template) {
var args = [].slice.call(arguments, 1);
var errMsg = util.format.bind(util, template).apply(null, args);
function typeError(template, ...args) {
var errMsg = util.format(template, ...args);
return new TypeError(errMsg);
}

Expand All @@ -130,15 +104,16 @@ function createHmacSigner(bits) {
checkIsSecretKey(secret);
thing = normalizeInput(thing);
var hmac = crypto.createHmac('sha' + bits, secret);
var sig = (hmac.update(thing), hmac.digest('base64'))
return fromBase64(sig);
hmac.update(thing);
var sig = hmac.digest('base64url')
return sig;
}
}

function createHmacVerifier(bits) {
return function verify(thing, signature, secret) {
var computedSig = createHmacSigner(bits)(thing, secret);
return bufferEqual(Buffer.from(signature), Buffer.from(computedSig));
return timingSafeEqual(Buffer.from(signature), Buffer.from(computedSig));
}
}

Expand All @@ -149,19 +124,19 @@ function createKeySigner(bits) {
// Even though we are specifying "RSA" here, this works with ECDSA
// keys as well.
var signer = crypto.createSign('RSA-SHA' + bits);
jimmywarting marked this conversation as resolved.
Show resolved Hide resolved
var sig = (signer.update(thing), signer.sign(privateKey, 'base64'));
return fromBase64(sig);
signer.update(thing);
var sig = signer.sign(privateKey, 'base64url');
return sig;
}
}

function createKeyVerifier(bits) {
return function verify(thing, signature, publicKey) {
checkIsPublicKey(publicKey);
thing = normalizeInput(thing);
signature = toBase64(signature);
var verifier = crypto.createVerify('RSA-SHA' + bits);
verifier.update(thing);
return verifier.verify(publicKey, signature, 'base64');
return verifier.verify(publicKey, signature, 'base64url');
}
}

Expand All @@ -170,27 +145,27 @@ function createPSSKeySigner(bits) {
checkIsPrivateKey(privateKey);
thing = normalizeInput(thing);
var signer = crypto.createSign('RSA-SHA' + bits);
var sig = (signer.update(thing), signer.sign({
signer.update(thing);
var sig = signer.sign({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
}, 'base64'));
return fromBase64(sig);
}, 'base64url');
return sig;
}
}

function createPSSKeyVerifier(bits) {
return function verify(thing, signature, publicKey) {
checkIsPublicKey(publicKey);
thing = normalizeInput(thing);
signature = toBase64(signature);
var verifier = crypto.createVerify('RSA-SHA' + bits);
verifier.update(thing);
return verifier.verify({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
}, signature, 'base64');
}, signature, 'base64url');
}
}

Expand Down
7 changes: 4 additions & 3 deletions package.json
Expand Up @@ -6,10 +6,11 @@
"directories": {
"test": "test"
},
"engines": {
"node": ">=14.18.0"
},
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
"ecdsa-sig-formatter": "1.0.11"
},
"devDependencies": {
"base64url": "^2.0.0",
Expand Down