Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
feat: replace keypair and ursa-optional with node crypto (#219)
Browse files Browse the repository at this point in the history
We use `ursa-optional` to geenrate RSA keypairs in node.js, falling back to `keypair` if compilation of `ursa-optional` failed at install time.

Node.js has supported generating RSA keypairs since 10.x so use that instead and remove the `ursa-optional` and `kepair` dependencies.

As a bonus node 15+ also supports `jwk` format keys everywhere so the `pem-jwk` dep can go too.

BREAKING CHANGE: requires node 15+
  • Loading branch information
achingbrain authored Dec 1, 2021
1 parent 42ed07a commit 759535c
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
node: [14, 16]
node: [16]
fail-fast: true
steps:
- uses: actions/checkout@v2
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@
"@noble/secp256k1": "^1.3.0",
"err-code": "^3.0.1",
"iso-random-stream": "^2.0.0",
"keypair": "^1.0.4",
"multiformats": "^9.4.5",
"node-forge": "^0.10.0",
"pem-jwk": "^2.0.0",
"protobufjs": "^6.11.2",
"uint8arrays": "^3.0.0",
"ursa-optional": "^0.10.1"
"uint8arrays": "^3.0.0"
},
"devDependencies": {
"@types/mocha": "^9.0.0",
Expand Down
58 changes: 18 additions & 40 deletions src/keys/rsa.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,23 @@
'use strict'

const crypto = require('crypto')
const promisify = require('util').promisify
const errcode = require('err-code')
const randomBytes = require('../random-bytes')
// @ts-check
/**
* @type {PrivateKey}
*/
let keypair
try {
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'keypair') {
throw new Error('Force keypair usage')
}

const ursa = require('ursa-optional') // throws if not compiled
keypair = ({ bits }) => {
const key = ursa.generatePrivateKey(bits)
return {
private: key.toPrivatePem(),
public: key.toPublicPem()
}
}
} catch (e) {
if (process.env.LP2P_FORCE_CRYPTO_LIB === 'ursa') {
throw e
}

keypair = require('keypair')
}
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
const keypair = promisify(crypto.generateKeyPair)

exports.utils = require('./rsa-utils')

exports.generateKey = async function (bits) { // eslint-disable-line require-await
const key = keypair({ bits })
const key = await keypair('rsa', {
modulusLength: bits,
publicKeyEncoding: { type: 'pkcs1', format: 'jwk' },
privateKeyEncoding: { type: 'pkcs1', format: 'jwk' }
})

return {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
privateKey: key.privateKey,
publicKey: key.publicKey
}
}

Expand All @@ -59,25 +39,23 @@ exports.unmarshalPrivateKey = async function (key) { // eslint-disable-line requ
exports.getRandomValues = randomBytes

exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
const pem = jwkToPem(key)
return sign.sign(pem)
return crypto.createSign('RSA-SHA256')
.update(msg)
.sign({ format: 'jwk', key: key })
}

exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
const pem = jwkToPem(key)
return verify.verify(pem, sig)
return crypto.createVerify('RSA-SHA256')
.update(msg)
.verify({ format: 'jwk', key: key }, sig)
}

const padding = crypto.constants.RSA_PKCS1_PADDING

exports.encrypt = function (key, bytes) {
return crypto.publicEncrypt({ key: jwkToPem(key), padding }, bytes)
return crypto.publicEncrypt({ format: 'jwk', key, padding }, bytes)
}

exports.decrypt = function (key, bytes) {
return crypto.privateDecrypt({ key: jwkToPem(key), padding }, bytes)
return crypto.privateDecrypt({ format: 'jwk', key, padding }, bytes)
}

0 comments on commit 759535c

Please sign in to comment.