feat: refactor to use async/await (#131)

BREAKING CHANGE: API refactored to use async/await

feat: WIP use async await
fix: passing tests
chore: update travis node.js versions
fix: skip ursa optional tests on windows
fix: benchmarks
docs: update docs
fix: remove broken and intested private key decrypt
chore: update deps
This commit is contained in:
Alan Shaw
2019-07-10 17:15:26 +01:00
committed by Jacob Heun
parent 5cd0e8cc1a
commit ad7107233e
32 changed files with 690 additions and 1261 deletions

View File

@ -1,12 +1,8 @@
'use strict'
const webcrypto = require('../webcrypto')
const nodeify = require('../nodeify')
const webcrypto = require('../webcrypto.js')
const BN = require('asn1.js').bignum
const util = require('../util')
const toBase64 = util.toBase64
const toBn = util.toBn
const { toBase64, toBn } = require('../util')
const bits = {
'P-256': 256,
@ -14,72 +10,66 @@ const bits = {
'P-521': 521
}
exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(webcrypto.subtle.generateKey(
exports.generateEphmeralKeyPair = async function (curve) {
const pair = await webcrypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: curve
},
true,
['deriveBits']
).then((pair) => {
// forcePrivate is used for testing only
const genSharedKey = (theirPub, forcePrivate, cb) => {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = undefined
}
)
let privateKey
// forcePrivate is used for testing only
const genSharedKey = async (theirPub, forcePrivate) => {
let privateKey
if (forcePrivate) {
privateKey = webcrypto.subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
name: 'ECDH',
namedCurve: curve
},
false,
['deriveBits']
)
} else {
privateKey = Promise.resolve(pair.privateKey)
}
const keys = Promise.all([
webcrypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
),
privateKey
])
nodeify(keys.then((keys) => webcrypto.subtle.deriveBits(
if (forcePrivate) {
privateKey = await webcrypto.subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
name: 'ECDH',
namedCurve: curve,
public: keys[0]
namedCurve: curve
},
keys[1],
bits[curve]
)).then((bits) => Buffer.from(bits)), cb)
false,
['deriveBits']
)
} else {
privateKey = pair.privateKey
}
return webcrypto.subtle.exportKey('jwk', pair.publicKey)
.then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
const keys = [
await webcrypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
),
privateKey
]
return Buffer.from(await webcrypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
public: keys[0]
},
keys[1],
bits[curve]
))
}
const publicKey = await webcrypto.subtle.exportKey('jwk', pair.publicKey)
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
}
const curveLengths = {

View File

@ -1,7 +1,6 @@
'use strict'
const crypto = require('crypto')
const nextTick = require('async/nextTick')
const curves = {
'P-256': 'prime256v1',
@ -9,33 +8,21 @@ const curves = {
'P-521': 'secp521r1'
}
exports.generateEphmeralKeyPair = function (curve, callback) {
exports.generateEphmeralKeyPair = async function (curve) { // eslint-disable-line require-await
if (!curves[curve]) {
return callback(new Error(`Unkown curve: ${curve}`))
throw new Error(`Unkown curve: ${curve}`)
}
const ecdh = crypto.createECDH(curves[curve])
ecdh.generateKeys()
nextTick(() => callback(null, {
return {
key: ecdh.getPublicKey(),
genSharedKey (theirPub, forcePrivate, cb) {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = null
}
async genSharedKey (theirPub, forcePrivate) { // eslint-disable-line require-await
if (forcePrivate) {
ecdh.setPrivateKey(forcePrivate.private)
}
let secret
try {
secret = ecdh.computeSecret(theirPub)
} catch (err) {
return cb(err)
}
nextTick(() => cb(null, secret))
return ecdh.computeSecret(theirPub)
}
}))
}
}

View File

@ -12,9 +12,8 @@ class Ed25519PublicKey {
this._key = ensureKey(key, crypto.publicKeyLength)
}
verify (data, sig, callback) {
ensure(callback)
crypto.hashAndVerify(this._key, sig, data, callback)
async verify (data, sig) { // eslint-disable-line require-await
return crypto.hashAndVerify(this._key, sig, data)
}
marshal () {
@ -32,9 +31,8 @@ class Ed25519PublicKey {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
}
}
@ -46,9 +44,8 @@ class Ed25519PrivateKey {
this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
}
sign (message, callback) {
ensure(callback)
crypto.hashAndSign(this._key, message, callback)
async sign (message) { // eslint-disable-line require-await
return crypto.hashAndSign(this._key, message)
}
get public () {
@ -74,9 +71,8 @@ class Ed25519PrivateKey {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
}
/**
@ -86,28 +82,19 @@ class Ed25519PrivateKey {
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
* @returns {Promise<String>}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
async id () {
const hash = await this.public.hash()
return bs58.encode(hash)
}
}
function unmarshalEd25519PrivateKey (bytes, callback) {
try {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
} catch (err) {
return callback(err)
}
function unmarshalEd25519PrivateKey (bytes) {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
callback(null, new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes))
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
}
function unmarshalEd25519PublicKey (bytes) {
@ -115,52 +102,14 @@ function unmarshalEd25519PublicKey (bytes) {
return new Ed25519PublicKey(bytes)
}
function generateKeyPair (_bits, cb) {
if (cb === undefined && typeof _bits === 'function') {
cb = _bits
}
crypto.generateKey((err, keys) => {
if (err) {
return cb(err)
}
let privkey
try {
privkey = new Ed25519PrivateKey(keys.secretKey, keys.publicKey)
} catch (err) {
cb(err)
return
}
cb(null, privkey)
})
async function generateKeyPair () {
const { secretKey, publicKey } = await crypto.generateKey()
return new Ed25519PrivateKey(secretKey, publicKey)
}
function generateKeyPairFromSeed (seed, _bits, cb) {
if (cb === undefined && typeof _bits === 'function') {
cb = _bits
}
crypto.generateKeyFromSeed(seed, (err, keys) => {
if (err) {
return cb(err)
}
let privkey
try {
privkey = new Ed25519PrivateKey(keys.secretKey, keys.publicKey)
} catch (err) {
cb(err)
return
}
cb(null, privkey)
})
}
function ensure (cb) {
if (typeof cb !== 'function') {
throw new Error('callback is required')
}
async function generateKeyPairFromSeed (seed) {
const { secretKey, publicKey } = await crypto.generateKeyFromSeed(seed)
return new Ed25519PrivateKey(secretKey, publicKey)
}
function ensureKey (key, length) {

View File

@ -1,51 +1,23 @@
'use strict'
const nacl = require('tweetnacl')
const nextTick = require('async/nextTick')
exports.publicKeyLength = nacl.sign.publicKeyLength
exports.privateKeyLength = nacl.sign.secretKeyLength
exports.generateKey = function (callback) {
nextTick(() => {
let result
try {
result = nacl.sign.keyPair()
} catch (err) {
return callback(err)
}
callback(null, result)
})
exports.generateKey = async function () { // eslint-disable-line require-await
return nacl.sign.keyPair()
}
// seed should be a 32 byte uint8array
exports.generateKeyFromSeed = function (seed, callback) {
nextTick(() => {
let result
try {
result = nacl.sign.keyPair.fromSeed(seed)
} catch (err) {
return callback(err)
}
callback(null, result)
})
exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await
return nacl.sign.keyPair.fromSeed(seed)
}
exports.hashAndSign = function (key, msg, callback) {
nextTick(() => {
callback(null, Buffer.from(nacl.sign.detached(msg, key)))
})
exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await
return Buffer.from(nacl.sign.detached(msg, key))
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nextTick(() => {
let result
try {
result = nacl.sign.detached.verify(msg, sig, key)
} catch (err) {
return callback(err)
}
callback(null, result)
})
exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await
return nacl.sign.detached.verify(msg, sig, key)
}

View File

@ -6,6 +6,4 @@ const ecdh = require('./ecdh')
// the shared secret key.
//
// Focuses only on ECDH now, but can be made more general in the future.
module.exports = (curve, callback) => {
ecdh.generateEphmeralKeyPair(curve, callback)
}
module.exports = async (curve) => ecdh.generateEphmeralKeyPair(curve) // eslint-disable-line require-await

View File

@ -27,27 +27,27 @@ exports.keyStretcher = require('./key-stretcher')
exports.generateEphemeralKeyPair = require('./ephemeral-keys')
// Generates a keypair of the given type and bitsize
exports.generateKeyPair = (type, bits, cb) => {
exports.generateKeyPair = async (type, bits) => { // eslint-disable-line require-await
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
throw new Error('invalid or unsupported key type')
}
key.generateKeyPair(bits, cb)
return key.generateKeyPair(bits)
}
// Generates a keypair of the given type and bitsize
// seed is a 32 byte uint8array
exports.generateKeyPairFromSeed = (type, seed, bits, cb) => {
exports.generateKeyPairFromSeed = async (type, seed, bits) => { // eslint-disable-line require-await
let key = supportedKeys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
throw new Error('invalid or unsupported key type')
}
if (type.toLowerCase() !== 'ed25519') {
return cb(new Error('Seed key derivation is unimplemented for RSA or secp256k1'))
throw new Error('Seed key derivation is unimplemented for RSA or secp256k1')
}
key.generateKeyPairFromSeed(seed, bits, cb)
return key.generateKeyPairFromSeed(seed, bits)
}
// Converts a protobuf serialized public key into its
@ -84,29 +84,23 @@ exports.marshalPublicKey = (key, type) => {
// Converts a protobuf serialized private key into its
// representative object
exports.unmarshalPrivateKey = (buf, callback) => {
let decoded
try {
decoded = keysPBM.PrivateKey.decode(buf)
} catch (err) {
return callback(err)
}
exports.unmarshalPrivateKey = async (buf) => { // eslint-disable-line require-await
const decoded = keysPBM.PrivateKey.decode(buf)
const data = decoded.Data
switch (decoded.Type) {
case keysPBM.KeyType.RSA:
return supportedKeys.rsa.unmarshalRsaPrivateKey(data, callback)
return supportedKeys.rsa.unmarshalRsaPrivateKey(data)
case keysPBM.KeyType.Ed25519:
return supportedKeys.ed25519.unmarshalEd25519PrivateKey(data, callback)
return supportedKeys.ed25519.unmarshalEd25519PrivateKey(data)
case keysPBM.KeyType.Secp256k1:
if (supportedKeys.secp256k1) {
return supportedKeys.secp256k1.unmarshalSecp256k1PrivateKey(data, callback)
return supportedKeys.secp256k1.unmarshalSecp256k1PrivateKey(data)
} else {
return callback(new Error('secp256k1 support requires libp2p-crypto-secp256k1 package'))
throw new Error('secp256k1 support requires libp2p-crypto-secp256k1 package')
}
default:
callback(new Error('invalid or unsupported key type'))
throw new Error('invalid or unsupported key type')
}
}
@ -120,16 +114,12 @@ exports.marshalPrivateKey = (key, type) => {
return key.bytes
}
exports.import = (pem, password, callback) => {
try {
const key = forge.pki.decryptRsaPrivateKey(pem, password)
if (key === null) {
throw new Error('Cannot read the key, most likely the password is wrong or not a RSA key')
}
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
der = Buffer.from(der.getBytes(), 'binary')
return supportedKeys.rsa.unmarshalRsaPrivateKey(der, callback)
} catch (err) {
callback(err)
exports.import = async (pem, password) => { // eslint-disable-line require-await
const key = forge.pki.decryptRsaPrivateKey(pem, password)
if (key === null) {
throw new Error('Cannot read the key, most likely the password is wrong or not a RSA key')
}
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
der = Buffer.from(der.getBytes(), 'binary')
return supportedKeys.rsa.unmarshalRsaPrivateKey(der)
}

View File

@ -1,6 +1,5 @@
'use strict'
const whilst = require('async/whilst')
const hmac = require('../hmac')
const cipherMap = {
@ -20,15 +19,15 @@ const cipherMap = {
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
module.exports = (cipherType, hash, secret, callback) => {
module.exports = async (cipherType, hash, secret) => {
const cipher = cipherMap[cipherType]
if (!cipher) {
return callback(new Error('unkown cipherType passed'))
throw new Error('unkown cipherType passed')
}
if (!hash) {
return callback(new Error('unkown hashType passed'))
throw new Error('unkown hashType passed')
}
const cipherKeySize = cipher.keySize
@ -37,72 +36,38 @@ module.exports = (cipherType, hash, secret, callback) => {
const seed = Buffer.from('key expansion')
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
hmac.create(hash, secret, (err, m) => {
if (err) {
return callback(err)
const m = await hmac.create(hash, secret)
let a = await m.digest(seed)
let result = []
let j = 0
while (j < resultLength) {
const b = await m.digest(Buffer.concat([a, seed]))
let todo = b.length
if (j + todo > resultLength) {
todo = resultLength - j
}
m.digest(seed, (err, a) => {
if (err) {
return callback(err)
}
result.push(b)
j += todo
a = await m.digest(a)
}
let result = []
let j = 0
const half = resultLength / 2
const resultBuffer = Buffer.concat(result)
const r1 = resultBuffer.slice(0, half)
const r2 = resultBuffer.slice(half, resultLength)
whilst(
() => j < resultLength,
stretch,
finish
)
function stretch (cb) {
m.digest(Buffer.concat([a, seed]), (err, b) => {
if (err) {
return cb(err)
}
let todo = b.length
if (j + todo > resultLength) {
todo = resultLength - j
}
result.push(b)
j += todo
m.digest(a, (err, _a) => {
if (err) {
return cb(err)
}
a = _a
cb()
})
})
}
function finish (err) {
if (err) {
return callback(err)
}
const half = resultLength / 2
const resultBuffer = Buffer.concat(result)
const r1 = resultBuffer.slice(0, half)
const r2 = resultBuffer.slice(half, resultLength)
const createKey = (res) => ({
iv: res.slice(0, ivSize),
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
macKey: res.slice(ivSize + cipherKeySize)
})
callback(null, {
k1: createKey(r1),
k2: createKey(r2)
})
}
})
const createKey = (res) => ({
iv: res.slice(0, ivSize),
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
macKey: res.slice(ivSize + cipherKeySize)
})
return {
k1: createKey(r1),
k2: createKey(r2)
}
}

View File

@ -12,4 +12,4 @@ message PublicKey {
message PrivateKey {
required KeyType Type = 1;
required bytes Data = 2;
}`
}`

View File

@ -1,13 +1,12 @@
'use strict'
const nodeify = require('../nodeify')
const webcrypto = require('../webcrypto')
const webcrypto = require('../webcrypto.js')
const randomBytes = require('../random-bytes')
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
nodeify(webcrypto.subtle.generateKey(
exports.generateKey = async function (bits) {
const pair = await webcrypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
@ -17,16 +16,18 @@ exports.generateKey = function (bits, callback) {
true,
['sign', 'verify']
)
.then(exportKey)
.then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
const keys = await exportKey(pair)
return {
privateKey: keys[0],
publicKey: keys[1]
}
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
const privateKey = webcrypto.subtle.importKey(
exports.unmarshalPrivateKey = async function (key) {
const privateKey = await webcrypto.subtle.importKey(
'jwk',
key,
{
@ -37,22 +38,26 @@ exports.unmarshalPrivateKey = function (key, callback) {
['sign']
)
nodeify(Promise.all([
const pair = [
privateKey,
derivePublicFromPrivate(key)
]).then((keys) => exportKey({
await derivePublicFromPrivate(key)
]
const keys = await exportKey({
privateKey: pair[0],
publicKey: pair[1]
})
return {
privateKey: keys[0],
publicKey: keys[1]
})).then((keys) => ({
privateKey: keys[0],
publicKey: keys[1]
})), callback)
}
}
exports.getRandomValues = randomBytes
exports.hashAndSign = function (key, msg, callback) {
nodeify(webcrypto.subtle.importKey(
exports.hashAndSign = async function (key, msg) {
const privateKey = await webcrypto.subtle.importKey(
'jwk',
key,
{
@ -61,17 +66,19 @@ exports.hashAndSign = function (key, msg, callback) {
},
false,
['sign']
).then((privateKey) => {
return webcrypto.subtle.sign(
{ name: 'RSASSA-PKCS1-v1_5' },
privateKey,
Uint8Array.from(msg)
)
}).then((sig) => Buffer.from(sig)), callback)
)
const sig = await webcrypto.subtle.sign(
{ name: 'RSASSA-PKCS1-v1_5' },
privateKey,
Uint8Array.from(msg)
)
return Buffer.from(sig)
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nodeify(webcrypto.subtle.importKey(
exports.hashAndVerify = async function (key, sig, msg) {
const publicKey = await webcrypto.subtle.importKey(
'jwk',
key,
{
@ -80,14 +87,14 @@ exports.hashAndVerify = function (key, sig, msg, callback) {
},
false,
['verify']
).then((publicKey) => {
return webcrypto.subtle.verify(
{ name: 'RSASSA-PKCS1-v1_5' },
publicKey,
sig,
msg
)
}), callback)
)
return webcrypto.subtle.verify(
{ name: 'RSASSA-PKCS1-v1_5' },
publicKey,
sig,
msg
)
}
function exportKey (pair) {

View File

@ -3,7 +3,6 @@
const multihashing = require('multihashing-async')
const protobuf = require('protons')
const bs58 = require('bs58')
const nextTick = require('async/nextTick')
const crypto = require('./rsa')
const pbm = protobuf(require('./keys.proto'))
@ -16,9 +15,8 @@ class RsaPublicKey {
this._key = key
}
verify (data, sig, callback) {
ensure(callback)
crypto.hashAndVerify(this._key, sig, data, callback)
async verify (data, sig) { // eslint-disable-line require-await
return crypto.hashAndVerify(this._key, sig, data)
}
marshal () {
@ -40,9 +38,8 @@ class RsaPublicKey {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
}
}
@ -58,9 +55,8 @@ class RsaPrivateKey {
return crypto.getRandomValues(16)
}
sign (message, callback) {
ensure(callback)
crypto.hashAndSign(this._key, message, callback)
async sign (message) { // eslint-disable-line require-await
return crypto.hashAndSign(this._key, message)
}
get public () {
@ -71,10 +67,6 @@ class RsaPrivateKey {
return new RsaPublicKey(this._publicKey)
}
decrypt (msg, callback) {
crypto.decrypt(this._key, msg, callback)
}
marshal () {
return crypto.utils.jwkToPkcs1(this._key)
}
@ -90,9 +82,8 @@ class RsaPrivateKey {
return this.bytes.equals(key.bytes)
}
hash (callback) {
ensure(callback)
multihashing(this.bytes, 'sha2-256', callback)
async hash () { // eslint-disable-line require-await
return multihashing(this.bytes, 'sha2-256')
}
/**
@ -102,16 +93,11 @@ class RsaPrivateKey {
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @param {function(Error, id)} callback
* @returns {undefined}
* @returns {Promise<String>}
*/
id (callback) {
this.public.hash((err, hash) => {
if (err) {
return callback(err)
}
callback(null, bs58.encode(hash))
})
async id () {
const hash = await this.public.hash()
return bs58.encode(hash)
}
/**
@ -119,87 +105,55 @@ class RsaPrivateKey {
*
* @param {string} [format] - Defaults to 'pkcs-8'.
* @param {string} password - The password to read the encrypted PEM
* @param {function(Error, KeyInfo)} callback
* @returns {undefined}
* @returns {KeyInfo}
*/
export (format, password, callback) {
if (typeof password === 'function') {
callback = password
async export (format, password) { // eslint-disable-line require-await
if (password == null) {
password = format
format = 'pkcs-8'
}
ensure(callback)
let pem = null
nextTick(() => {
let err = null
let pem = null
try {
const buffer = new forge.util.ByteBuffer(this.marshal())
const asn1 = forge.asn1.fromDer(buffer)
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
if (format === 'pkcs-8') {
const options = {
algorithm: 'aes256',
count: 10000,
saltSize: 128 / 8,
prfAlgorithm: 'sha512'
}
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
} else {
err = new Error(`Unknown export format '${format}'`)
}
} catch (_err) {
err = _err
const buffer = new forge.util.ByteBuffer(this.marshal())
const asn1 = forge.asn1.fromDer(buffer)
const privateKey = forge.pki.privateKeyFromAsn1(asn1)
if (format === 'pkcs-8') {
const options = {
algorithm: 'aes256',
count: 10000,
saltSize: 128 / 8,
prfAlgorithm: 'sha512'
}
pem = forge.pki.encryptRsaPrivateKey(privateKey, password, options)
} else {
throw new Error(`Unknown export format '${format}'`)
}
callback(err, pem)
})
return pem
}
}
function unmarshalRsaPrivateKey (bytes, callback) {
async function unmarshalRsaPrivateKey (bytes) {
const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
const keys = await crypto.unmarshalPrivateKey(jwk)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
}
function unmarshalRsaPublicKey (bytes) {
const jwk = crypto.utils.pkixToJwk(bytes)
return new RsaPublicKey(jwk)
}
function fromJwk (jwk, callback) {
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
async function fromJwk (jwk) {
const keys = await crypto.unmarshalPrivateKey(jwk)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
}
function generateKeyPair (bits, callback) {
crypto.generateKey(bits, (err, keys) => {
if (err) {
return callback(err)
}
callback(null, new RsaPrivateKey(keys.privateKey, keys.publicKey))
})
}
function ensure (callback) {
if (typeof callback !== 'function') {
throw new Error('callback is required')
}
async function generateKeyPair (bits) {
const keys = await crypto.generateKey(bits)
return new RsaPrivateKey(keys.privateKey, keys.publicKey)
}
module.exports = {

View File

@ -2,7 +2,6 @@
const crypto = require('crypto')
const randomBytes = require('../random-bytes')
const nextTick = require('async/nextTick')
let keypair
try {
@ -30,70 +29,41 @@ const jwkToPem = require('pem-jwk').jwk2pem
exports.utils = require('./rsa-utils')
exports.generateKey = function (bits, callback) {
nextTick(() => {
let result
try {
const key = keypair({ bits: bits })
result = {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
}
} catch (err) {
return callback(err)
}
callback(null, result)
})
exports.generateKey = async function (bits) { // eslint-disable-line require-await
const key = keypair({ bits })
return {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
}
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
nextTick(() => {
if (!key) {
return callback(new Error('Key is invalid'))
exports.unmarshalPrivateKey = async function (key) { // eslint-disable-line require-await
if (!key) {
throw new Error('Key is invalid')
}
return {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
})
}
}
exports.getRandomValues = randomBytes
exports.hashAndSign = function (key, msg, callback) {
nextTick(() => {
let result
try {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
const pem = jwkToPem(key)
result = sign.sign(pem)
} catch (err) {
return callback(new Error('Key or message is invalid!: ' + err.message))
}
callback(null, result)
})
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)
}
exports.hashAndVerify = function (key, sig, msg, callback) {
nextTick(() => {
let result
try {
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
const pem = jwkToPem(key)
result = verify.verify(pem, sig)
} catch (err) {
return callback(new Error('Key or message is invalid!:' + err.message))
}
callback(null, result)
})
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)
}