mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-06-29 12:01:36 +00:00
feat(rsa): add fallback pure js fallback for webcrypto-ossl
This commit is contained in:
13
package.json
13
package.json
@ -8,13 +8,15 @@
|
|||||||
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js",
|
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js",
|
||||||
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js",
|
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js",
|
||||||
"./src/crypto/ecdh.js": "./src/crypto/ecdh-browser.js",
|
"./src/crypto/ecdh.js": "./src/crypto/ecdh-browser.js",
|
||||||
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js"
|
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js",
|
||||||
|
"./src/crypto/rsa.js": "./src/crypto/rsa-browser.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "aegir-lint",
|
"lint": "aegir-lint",
|
||||||
"build": "aegir-build",
|
"build": "aegir-build",
|
||||||
"test": "aegir-test",
|
"test": "npm run test:node && npm run test:no-webcrypto && npm run test:browser",
|
||||||
"test:node": "aegir-test --env node",
|
"test:node": "aegir-test --env node",
|
||||||
|
"test:no-webcrypto": "NO_WEBCRYPTO=true aegir-test --env node",
|
||||||
"test:browser": "aegir-test --env browser",
|
"test:browser": "aegir-test --env browser",
|
||||||
"release": "aegir-release",
|
"release": "aegir-release",
|
||||||
"release-minor": "aegir-release --type minor",
|
"release-minor": "aegir-release --type minor",
|
||||||
@ -34,10 +36,12 @@
|
|||||||
"asn1.js": "^4.8.1",
|
"asn1.js": "^4.8.1",
|
||||||
"async": "^2.1.2",
|
"async": "^2.1.2",
|
||||||
"browserify-aes": "^1.0.6",
|
"browserify-aes": "^1.0.6",
|
||||||
|
"keypair": "^1.0.0",
|
||||||
"multihashing-async": "^0.2.0",
|
"multihashing-async": "^0.2.0",
|
||||||
"node-webcrypto-ossl": "^1.0.13",
|
|
||||||
"nodeify": "^1.0.0",
|
"nodeify": "^1.0.0",
|
||||||
|
"pem-jwk": "^1.5.1",
|
||||||
"protocol-buffers": "^3.2.1",
|
"protocol-buffers": "^3.2.1",
|
||||||
|
"rsa-pem-to-jwk": "^1.1.3",
|
||||||
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
|
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -46,6 +50,9 @@
|
|||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"pre-commit": "^1.1.3"
|
"pre-commit": "^1.1.3"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"node-webcrypto-ossl": "^1.0.13"
|
||||||
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
"lint",
|
"lint",
|
||||||
"test"
|
"test"
|
||||||
|
@ -97,7 +97,7 @@ function marshalPublicKey (jwk) {
|
|||||||
const byteLen = curveLengths[jwk.crv]
|
const byteLen = curveLengths[jwk.crv]
|
||||||
|
|
||||||
return Buffer.concat([
|
return Buffer.concat([
|
||||||
Buffer([4]), // uncompressed point
|
new Buffer([4]), // uncompressed point
|
||||||
toBn(jwk.x).toBuffer('be', byteLen),
|
toBn(jwk.x).toBuffer('be', byteLen),
|
||||||
toBn(jwk.y).toBuffer('be', byteLen)
|
toBn(jwk.y).toBuffer('be', byteLen)
|
||||||
], 1 + byteLen * 2)
|
], 1 + byteLen * 2)
|
||||||
@ -107,7 +107,7 @@ function marshalPublicKey (jwk) {
|
|||||||
function unmarshalPublicKey (curve, key) {
|
function unmarshalPublicKey (curve, key) {
|
||||||
const byteLen = curveLengths[curve]
|
const byteLen = curveLengths[curve]
|
||||||
|
|
||||||
if (!key.slice(0, 1).equals(Buffer([4]))) {
|
if (!key.slice(0, 1).equals(new Buffer([4]))) {
|
||||||
throw new Error('Invalid key format')
|
throw new Error('Invalid key format')
|
||||||
}
|
}
|
||||||
const x = new BN(key.slice(1, byteLen + 1))
|
const x = new BN(key.slice(1, byteLen + 1))
|
||||||
|
119
src/crypto/rsa-browser.js
Normal file
119
src/crypto/rsa-browser.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const nodeify = require('nodeify')
|
||||||
|
|
||||||
|
const crypto = require('./webcrypto')()
|
||||||
|
|
||||||
|
exports.utils = require('./rsa-utils')
|
||||||
|
|
||||||
|
exports.generateKey = function (bits, callback) {
|
||||||
|
nodeify(crypto.subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
modulusLength: bits,
|
||||||
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||||
|
hash: {name: 'SHA-256'}
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign', 'verify']
|
||||||
|
)
|
||||||
|
.then(exportKey)
|
||||||
|
.then((keys) => ({
|
||||||
|
privateKey: keys[0],
|
||||||
|
publicKey: keys[1]
|
||||||
|
})), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a jwk key
|
||||||
|
exports.unmarshalPrivateKey = function (key, callback) {
|
||||||
|
const privateKey = crypto.subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: {name: 'SHA-256'}
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign']
|
||||||
|
)
|
||||||
|
|
||||||
|
nodeify(Promise.all([
|
||||||
|
privateKey,
|
||||||
|
derivePublicFromPrivate(key)
|
||||||
|
]).then((keys) => exportKey({
|
||||||
|
privateKey: keys[0],
|
||||||
|
publicKey: keys[1]
|
||||||
|
})).then((keys) => ({
|
||||||
|
privateKey: keys[0],
|
||||||
|
publicKey: keys[1]
|
||||||
|
})), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getRandomValues = function (arr) {
|
||||||
|
return Buffer.from(crypto.getRandomValues(arr))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndSign = function (key, msg, callback) {
|
||||||
|
nodeify(crypto.subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: {name: 'SHA-256'}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['sign']
|
||||||
|
).then((privateKey) => {
|
||||||
|
return crypto.subtle.sign(
|
||||||
|
{name: 'RSASSA-PKCS1-v1_5'},
|
||||||
|
privateKey,
|
||||||
|
Uint8Array.from(msg)
|
||||||
|
)
|
||||||
|
}).then((sig) => Buffer.from(sig)), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.hashAndVerify = function (key, sig, msg, callback) {
|
||||||
|
nodeify(crypto.subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: {name: 'SHA-256'}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['verify']
|
||||||
|
).then((publicKey) => {
|
||||||
|
return crypto.subtle.verify(
|
||||||
|
{name: 'RSASSA-PKCS1-v1_5'},
|
||||||
|
publicKey,
|
||||||
|
sig,
|
||||||
|
msg
|
||||||
|
)
|
||||||
|
}), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportKey (pair) {
|
||||||
|
return Promise.all([
|
||||||
|
crypto.subtle.exportKey('jwk', pair.privateKey),
|
||||||
|
crypto.subtle.exportKey('jwk', pair.publicKey)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function derivePublicFromPrivate (jwKey) {
|
||||||
|
return crypto.subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
{
|
||||||
|
kty: jwKey.kty,
|
||||||
|
n: jwKey.n,
|
||||||
|
e: jwKey.e,
|
||||||
|
alg: jwKey.alg,
|
||||||
|
kid: jwKey.kid
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'RSASSA-PKCS1-v1_5',
|
||||||
|
hash: {name: 'SHA-256'}
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['verify']
|
||||||
|
)
|
||||||
|
}
|
114
src/crypto/rsa-utils.js
Normal file
114
src/crypto/rsa-utils.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const asn1 = require('asn1.js')
|
||||||
|
|
||||||
|
const util = require('./util')
|
||||||
|
const toBase64 = util.toBase64
|
||||||
|
const toBn = util.toBn
|
||||||
|
|
||||||
|
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
|
||||||
|
this.seq().obj(
|
||||||
|
this.key('version').int(),
|
||||||
|
this.key('modulus').int(),
|
||||||
|
this.key('publicExponent').int(),
|
||||||
|
this.key('privateExponent').int(),
|
||||||
|
this.key('prime1').int(),
|
||||||
|
this.key('prime2').int(),
|
||||||
|
this.key('exponent1').int(),
|
||||||
|
this.key('exponent2').int(),
|
||||||
|
this.key('coefficient').int()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
|
||||||
|
this.seq().obj(
|
||||||
|
this.key('algorithm').objid({
|
||||||
|
'1.2.840.113549.1.1.1': 'rsa'
|
||||||
|
}),
|
||||||
|
this.key('none').optional().null_(),
|
||||||
|
this.key('curve').optional().objid(),
|
||||||
|
this.key('params').optional().seq().obj(
|
||||||
|
this.key('p').int(),
|
||||||
|
this.key('q').int(),
|
||||||
|
this.key('g').int()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const PublicKey = asn1.define('RSAPublicKey', function () {
|
||||||
|
this.seq().obj(
|
||||||
|
this.key('algorithm').use(AlgorithmIdentifier),
|
||||||
|
this.key('subjectPublicKey').bitstr()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
|
||||||
|
this.seq().obj(
|
||||||
|
this.key('modulus').int(),
|
||||||
|
this.key('publicExponent').int()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Convert a PKCS#1 in ASN1 DER format to a JWK key
|
||||||
|
exports.pkcs1ToJwk = function (bytes) {
|
||||||
|
const asn1 = RSAPrivateKey.decode(bytes, 'der')
|
||||||
|
|
||||||
|
return {
|
||||||
|
kty: 'RSA',
|
||||||
|
n: toBase64(asn1.modulus),
|
||||||
|
e: toBase64(asn1.publicExponent),
|
||||||
|
d: toBase64(asn1.privateExponent),
|
||||||
|
p: toBase64(asn1.prime1),
|
||||||
|
q: toBase64(asn1.prime2),
|
||||||
|
dp: toBase64(asn1.exponent1),
|
||||||
|
dq: toBase64(asn1.exponent2),
|
||||||
|
qi: toBase64(asn1.coefficient),
|
||||||
|
alg: 'RS256',
|
||||||
|
kid: '2011-04-29'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a JWK key into PKCS#1 in ASN1 DER format
|
||||||
|
exports.jwkToPkcs1 = function (jwk) {
|
||||||
|
return RSAPrivateKey.encode({
|
||||||
|
version: 0,
|
||||||
|
modulus: toBn(jwk.n),
|
||||||
|
publicExponent: toBn(jwk.e),
|
||||||
|
privateExponent: toBn(jwk.d),
|
||||||
|
prime1: toBn(jwk.p),
|
||||||
|
prime2: toBn(jwk.q),
|
||||||
|
exponent1: toBn(jwk.dp),
|
||||||
|
exponent2: toBn(jwk.dq),
|
||||||
|
coefficient: toBn(jwk.qi)
|
||||||
|
}, 'der')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a PKCIX in ASN1 DER format to a JWK key
|
||||||
|
exports.pkixToJwk = function (bytes) {
|
||||||
|
const ndata = PublicKey.decode(bytes, 'der')
|
||||||
|
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
|
||||||
|
|
||||||
|
return {
|
||||||
|
kty: 'RSA',
|
||||||
|
n: toBase64(asn1.modulus),
|
||||||
|
e: toBase64(asn1.publicExponent),
|
||||||
|
alg: 'RS256',
|
||||||
|
kid: '2011-04-29'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a JWK key to PKCIX in ASN1 DER format
|
||||||
|
exports.jwkToPkix = function (jwk) {
|
||||||
|
return PublicKey.encode({
|
||||||
|
algorithm: {
|
||||||
|
algorithm: 'rsa',
|
||||||
|
none: null
|
||||||
|
},
|
||||||
|
subjectPublicKey: {
|
||||||
|
data: RSAPublicKey.encode({
|
||||||
|
modulus: toBn(jwk.n),
|
||||||
|
publicExponent: toBn(jwk.e)
|
||||||
|
}, 'der')
|
||||||
|
}
|
||||||
|
}, 'der')
|
||||||
|
}
|
@ -1,228 +1,80 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const nodeify = require('nodeify')
|
// Node.js land
|
||||||
const asn1 = require('asn1.js')
|
// First we look if node-webrypto-ossl is available
|
||||||
|
// otherwise we fall back to using keypair + node core
|
||||||
|
|
||||||
const util = require('./util')
|
let webcrypto
|
||||||
const toBase64 = util.toBase64
|
try {
|
||||||
const toBn = util.toBn
|
webcrypto = require('node-webcrypto-ossl')
|
||||||
const crypto = require('./webcrypto')()
|
} catch (err) {
|
||||||
|
// not available, use the code below
|
||||||
exports.generateKey = function (bits, callback) {
|
|
||||||
nodeify(crypto.subtle.generateKey(
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
modulusLength: bits,
|
|
||||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign', 'verify']
|
|
||||||
)
|
|
||||||
.then(exportKey)
|
|
||||||
.then((keys) => ({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})), callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a jwk key
|
if (webcrypto && !process.env.NO_WEBCRYPTO) {
|
||||||
exports.unmarshalPrivateKey = function (key, callback) {
|
module.exports = require('./rsa-browser')
|
||||||
const privateKey = crypto.subtle.importKey(
|
} else {
|
||||||
'jwk',
|
const crypto = require('crypto')
|
||||||
key,
|
const keypair = require('keypair')
|
||||||
{
|
const setImmediate = require('async/setImmediate')
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
const pemToJwk = require('pem-jwk').pem2jwk
|
||||||
hash: {name: 'SHA-256'}
|
const jwkToPem = require('pem-jwk').jwk2pem
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign']
|
|
||||||
)
|
|
||||||
|
|
||||||
nodeify(Promise.all([
|
exports.utils = require('./rsa-utils')
|
||||||
privateKey,
|
|
||||||
derivePublicFromPrivate(key)
|
|
||||||
]).then((keys) => exportKey({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})).then((keys) => ({
|
|
||||||
privateKey: keys[0],
|
|
||||||
publicKey: keys[1]
|
|
||||||
})), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getRandomValues = function (arr) {
|
exports.generateKey = function (bits, callback) {
|
||||||
return Buffer.from(crypto.getRandomValues(arr))
|
const done = (err, res) => setImmediate(() => {
|
||||||
}
|
callback(err, res)
|
||||||
|
})
|
||||||
|
|
||||||
exports.hashAndSign = function (key, msg, callback) {
|
let key
|
||||||
nodeify(crypto.subtle.importKey(
|
try {
|
||||||
'jwk',
|
key = keypair({
|
||||||
key,
|
bits: bits
|
||||||
{
|
})
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
} catch (err) {
|
||||||
hash: {name: 'SHA-256'}
|
done(err)
|
||||||
},
|
return
|
||||||
false,
|
}
|
||||||
['sign']
|
|
||||||
).then((privateKey) => {
|
|
||||||
return crypto.subtle.sign(
|
|
||||||
{name: 'RSASSA-PKCS1-v1_5'},
|
|
||||||
privateKey,
|
|
||||||
Uint8Array.from(msg)
|
|
||||||
)
|
|
||||||
}).then((sig) => Buffer.from(sig)), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.hashAndVerify = function (key, sig, msg, callback) {
|
done(null, {
|
||||||
nodeify(crypto.subtle.importKey(
|
privateKey: pemToJwk(key.private),
|
||||||
'jwk',
|
publicKey: pemToJwk(key.public)
|
||||||
key,
|
})
|
||||||
{
|
}
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['verify']
|
|
||||||
).then((publicKey) => {
|
|
||||||
return crypto.subtle.verify(
|
|
||||||
{name: 'RSASSA-PKCS1-v1_5'},
|
|
||||||
publicKey,
|
|
||||||
sig,
|
|
||||||
msg
|
|
||||||
)
|
|
||||||
}), callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function exportKey (pair) {
|
// Takes a jwk key
|
||||||
return Promise.all([
|
exports.unmarshalPrivateKey = function (key, callback) {
|
||||||
crypto.subtle.exportKey('jwk', pair.privateKey),
|
callback(null, {
|
||||||
crypto.subtle.exportKey('jwk', pair.publicKey)
|
privateKey: key,
|
||||||
])
|
publicKey: {
|
||||||
}
|
kty: key.kty,
|
||||||
|
n: key.n,
|
||||||
|
e: key.e
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function derivePublicFromPrivate (jwKey) {
|
exports.getRandomValues = function (arr) {
|
||||||
return crypto.subtle.importKey(
|
return crypto.randomBytes(arr.length)
|
||||||
'jwk',
|
}
|
||||||
{
|
|
||||||
kty: jwKey.kty,
|
|
||||||
n: jwKey.n,
|
|
||||||
e: jwKey.e,
|
|
||||||
alg: jwKey.alg,
|
|
||||||
kid: jwKey.kid
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'RSASSA-PKCS1-v1_5',
|
|
||||||
hash: {name: 'SHA-256'}
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['verify']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const RSAPrivateKey = asn1.define('RSAPrivateKey', function () {
|
exports.hashAndSign = function (key, msg, callback) {
|
||||||
this.seq().obj(
|
const sign = crypto.createSign('RSA-SHA256')
|
||||||
this.key('version').int(),
|
|
||||||
this.key('modulus').int(),
|
|
||||||
this.key('publicExponent').int(),
|
|
||||||
this.key('privateExponent').int(),
|
|
||||||
this.key('prime1').int(),
|
|
||||||
this.key('prime2').int(),
|
|
||||||
this.key('exponent1').int(),
|
|
||||||
this.key('exponent2').int(),
|
|
||||||
this.key('coefficient').int()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
|
sign.update(msg)
|
||||||
this.seq().obj(
|
setImmediate(() => {
|
||||||
this.key('algorithm').objid({
|
callback(null, sign.sign(jwkToPem(key)))
|
||||||
'1.2.840.113549.1.1.1': 'rsa'
|
})
|
||||||
}),
|
}
|
||||||
this.key('none').optional().null_(),
|
|
||||||
this.key('curve').optional().objid(),
|
|
||||||
this.key('params').optional().seq().obj(
|
|
||||||
this.key('p').int(),
|
|
||||||
this.key('q').int(),
|
|
||||||
this.key('g').int()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const PublicKey = asn1.define('RSAPublicKey', function () {
|
exports.hashAndVerify = function (key, sig, msg, callback) {
|
||||||
this.seq().obj(
|
const verify = crypto.createVerify('RSA-SHA256')
|
||||||
this.key('algorithm').use(AlgorithmIdentifier),
|
|
||||||
this.key('subjectPublicKey').bitstr()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const RSAPublicKey = asn1.define('RSAPublicKey', function () {
|
verify.update(msg)
|
||||||
this.seq().obj(
|
|
||||||
this.key('modulus').int(),
|
|
||||||
this.key('publicExponent').int()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Convert a PKCS#1 in ASN1 DER format to a JWK key
|
setImmediate(() => {
|
||||||
exports.pkcs1ToJwk = function (bytes) {
|
callback(null, verify.verify(jwkToPem(key), sig))
|
||||||
const asn1 = RSAPrivateKey.decode(bytes, 'der')
|
})
|
||||||
|
|
||||||
return {
|
|
||||||
kty: 'RSA',
|
|
||||||
n: toBase64(asn1.modulus),
|
|
||||||
e: toBase64(asn1.publicExponent),
|
|
||||||
d: toBase64(asn1.privateExponent),
|
|
||||||
p: toBase64(asn1.prime1),
|
|
||||||
q: toBase64(asn1.prime2),
|
|
||||||
dp: toBase64(asn1.exponent1),
|
|
||||||
dq: toBase64(asn1.exponent2),
|
|
||||||
qi: toBase64(asn1.coefficient),
|
|
||||||
alg: 'RS256',
|
|
||||||
kid: '2011-04-29'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a JWK key into PKCS#1 in ASN1 DER format
|
|
||||||
exports.jwkToPkcs1 = function (jwk) {
|
|
||||||
return RSAPrivateKey.encode({
|
|
||||||
version: 0,
|
|
||||||
modulus: toBn(jwk.n),
|
|
||||||
publicExponent: toBn(jwk.e),
|
|
||||||
privateExponent: toBn(jwk.d),
|
|
||||||
prime1: toBn(jwk.p),
|
|
||||||
prime2: toBn(jwk.q),
|
|
||||||
exponent1: toBn(jwk.dp),
|
|
||||||
exponent2: toBn(jwk.dq),
|
|
||||||
coefficient: toBn(jwk.qi)
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a PKCIX in ASN1 DER format to a JWK key
|
|
||||||
exports.pkixToJwk = function (bytes) {
|
|
||||||
const ndata = PublicKey.decode(bytes, 'der')
|
|
||||||
const asn1 = RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')
|
|
||||||
|
|
||||||
return {
|
|
||||||
kty: 'RSA',
|
|
||||||
n: toBase64(asn1.modulus),
|
|
||||||
e: toBase64(asn1.publicExponent),
|
|
||||||
alg: 'RS256',
|
|
||||||
kid: '2011-04-29'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a JWK key to PKCIX in ASN1 DER format
|
|
||||||
exports.jwkToPkix = function (jwk) {
|
|
||||||
return PublicKey.encode({
|
|
||||||
algorithm: {
|
|
||||||
algorithm: 'rsa',
|
|
||||||
none: null
|
|
||||||
},
|
|
||||||
subjectPublicKey: {
|
|
||||||
data: RSAPublicKey.encode({
|
|
||||||
modulus: toBn(jwk.n),
|
|
||||||
publicExponent: toBn(jwk.e)
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
||||||
}, 'der')
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
module.exports = function getWebCrypto () {
|
module.exports = function getWebCrypto () {
|
||||||
|
try {
|
||||||
const WebCrypto = require('node-webcrypto-ossl')
|
const WebCrypto = require('node-webcrypto-ossl')
|
||||||
const webCrypto = new WebCrypto()
|
const webCrypto = new WebCrypto()
|
||||||
return webCrypto
|
return webCrypto
|
||||||
|
} catch (err) {
|
||||||
|
// fallback to other things
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class RsaPublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
marshal () {
|
marshal () {
|
||||||
return crypto.jwkToPkix(this._key)
|
return crypto.utils.jwkToPkix(this._key)
|
||||||
}
|
}
|
||||||
|
|
||||||
get bytes () {
|
get bytes () {
|
||||||
@ -71,7 +71,7 @@ class RsaPrivateKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
marshal () {
|
marshal () {
|
||||||
return crypto.jwkToPkcs1(this._key)
|
return crypto.utils.jwkToPkcs1(this._key)
|
||||||
}
|
}
|
||||||
|
|
||||||
get bytes () {
|
get bytes () {
|
||||||
@ -92,7 +92,7 @@ class RsaPrivateKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalRsaPrivateKey (bytes, callback) {
|
function unmarshalRsaPrivateKey (bytes, callback) {
|
||||||
const jwk = crypto.pkcs1ToJwk(bytes)
|
const jwk = crypto.utils.pkcs1ToJwk(bytes)
|
||||||
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
|
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err)
|
return callback(err)
|
||||||
@ -103,7 +103,7 @@ function unmarshalRsaPrivateKey (bytes, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalRsaPublicKey (bytes) {
|
function unmarshalRsaPublicKey (bytes) {
|
||||||
const jwk = crypto.pkixToJwk(bytes)
|
const jwk = crypto.utils.pkixToJwk(bytes)
|
||||||
|
|
||||||
return new RsaPublicKey(jwk)
|
return new RsaPublicKey(jwk)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user