Compare commits

...

18 Commits

Author SHA1 Message Date
David Dias
cf7ed6fa49 chore: release version v0.7.4 2016-12-06 00:07:11 +00:00
David Dias
c1ffa41697 chore: update contributors 2016-12-06 00:07:11 +00:00
nikuda
933119445f fix(utils): make util.toBase64 browserify compatible
`bn.toArrayLike` is used instead of `bn.toBuffer`, to ensure compatibility with browserify.
2016-12-03 09:32:07 +01:00
David Dias
a4e6f9dd83 chore: release version v0.7.3 2016-12-01 11:43:46 +00:00
David Dias
e252db300c chore: update contributors 2016-12-01 11:43:46 +00:00
David Dias
98b37d49c4 feat: add randomBytes function (#45)
* feat: add randomBytes function

* fix: apply CR
2016-12-01 11:42:19 +00:00
David Dias
f979fcd3c2 chore: release version v0.7.2 2016-11-30 11:27:17 +00:00
David Dias
0af48bbebc chore: update contributors 2016-11-30 11:27:16 +00:00
David Dias
3f9d8d557c Merge pull request #42 from libp2p/feat/better-compat
Better compatability
2016-11-30 11:23:14 +00:00
Friedel Ziegelmayer
91a3b50ac9 feat(deps): update to multihashing-async@0.3.0 2016-11-29 18:11:58 +01:00
Friedel Ziegelmayer
148d16ab25 feat(rsa): add fallback pure js fallback for webcrypto-ossl 2016-11-29 17:54:41 +01:00
Friedel Ziegelmayer
6d15450438 feat(ecdh): use node core instead of webcrypto-ossl 2016-11-29 16:36:56 +01:00
David Dias
ebe1cecdeb Merge pull request #39 from libp2p/greenkeeper-protocol-buffers-3.2.1
protocol-buffers@3.2.1
2016-11-26 13:21:08 +01:00
greenkeeperio-bot
904cfb27bd chore(package): update protocol-buffers to version 3.2.1
https://greenkeeper.io/
2016-11-26 06:11:28 +01:00
Friedel Ziegelmayer
7790beb207 Merge pull request #37 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.13
node-webcrypto-ossl@1.0.13 breaks build 🚨
2016-11-23 23:26:31 +01:00
greenkeeperio-bot
6308461f0f chore(package): update node-webcrypto-ossl to version 1.0.13
https://greenkeeper.io/
2016-11-23 22:20:49 +01:00
Friedel Ziegelmayer
95a0f1f0c2 Merge pull request #34 from libp2p/greenkeeper-node-webcrypto-ossl-1.0.10
node-webcrypto-ossl@1.0.10 breaks build 🚨
2016-11-16 10:53:36 +01:00
greenkeeperio-bot
0c64122342 chore(package): update node-webcrypto-ossl to version 1.0.10
https://greenkeeper.io/
2016-11-15 07:46:24 +01:00
15 changed files with 564 additions and 328 deletions

View File

@@ -185,6 +185,11 @@ Converts a private key object into a protobuf serialized private key.
Converts a protobuf serialized private key into its representative object.
### `randomBytes(number)`
- `number: Number`
Generates a Buffer with length `number` populated by random bytes.
## Contribute

View File

@@ -1,19 +1,22 @@
{
"name": "libp2p-crypto",
"version": "0.7.1",
"version": "0.7.4",
"description": "Crypto primitives for libp2p",
"main": "src/index.js",
"browser": {
"node-webcrypto-ossl": false,
"./src/crypto/webcrypto.js": "./src/crypto/webcrypto-browser.js",
"./src/crypto/hmac.js": "./src/crypto/hmac-browser.js",
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js"
"./src/crypto/ecdh.js": "./src/crypto/ecdh-browser.js",
"./src/crypto/ciphers.js": "./src/crypto/ciphers-browser.js",
"./src/crypto/rsa.js": "./src/crypto/rsa-browser.js"
},
"scripts": {
"lint": "aegir-lint",
"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:no-webcrypto": "NO_WEBCRYPTO=true aegir-test --env node",
"test:browser": "aegir-test --env browser",
"release": "aegir-release",
"release-minor": "aegir-release --type minor",
@@ -33,10 +36,12 @@
"asn1.js": "^4.8.1",
"async": "^2.1.2",
"browserify-aes": "^1.0.6",
"multihashing-async": "^0.2.0",
"node-webcrypto-ossl": "^1.0.7",
"keypair": "^1.0.0",
"multihashing-async": "^0.3.0",
"nodeify": "^1.0.0",
"protocol-buffers": "^3.1.6",
"pem-jwk": "^1.5.1",
"protocol-buffers": "^3.2.1",
"rsa-pem-to-jwk": "^1.1.3",
"webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master"
},
"devDependencies": {
@@ -45,6 +50,9 @@
"chai": "^3.5.0",
"pre-commit": "^1.1.3"
},
"optionalDependencies": {
"node-webcrypto-ossl": "^1.0.13"
},
"pre-commit": [
"lint",
"test"

129
src/crypto/ecdh-browser.js Normal file
View File

@@ -0,0 +1,129 @@
'use strict'
const crypto = require('./webcrypto')()
const nodeify = require('nodeify')
const BN = require('asn1.js').bignum
const util = require('./util')
const toBase64 = util.toBase64
const toBn = util.toBn
const bits = {
'P-256': 256,
'P-384': 384,
'P-521': 521
}
exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(crypto.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
if (forcePrivate) {
privateKey = crypto.subtle.importKey(
'jwk',
unmarshalPrivateKey(curve, forcePrivate),
{
name: 'ECDH',
namedCurve: curve
},
false,
['deriveBits']
)
} else {
privateKey = Promise.resolve(pair.privateKey)
}
const keys = Promise.all([
crypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
),
privateKey
])
nodeify(keys.then((keys) => crypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
public: keys[0]
},
keys[1],
bits[curve]
)).then((bits) => Buffer.from(bits)), cb)
}
return crypto.subtle.exportKey(
'jwk',
pair.publicKey
).then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
}
const curveLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
// Marshal converts a jwk encodec ECDH public key into the
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
// go-ipfs uses)
function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv]
return Buffer.concat([
new Buffer([4]), // uncompressed point
toBn(jwk.x).toBuffer('be', byteLen),
toBn(jwk.y).toBuffer('be', byteLen)
], 1 + byteLen * 2)
}
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(new Buffer([4]))) {
throw new Error('Invalid key format')
}
const x = new BN(key.slice(1, byteLen + 1))
const y = new BN(key.slice(1 + byteLen))
return {
kty: 'EC',
crv: curve,
x: toBase64(x),
y: toBase64(y),
ext: true
}
}
function unmarshalPrivateKey (curve, key) {
const result = unmarshalPublicKey(curve, key.public)
result.d = toBase64(new BN(key.private))
return result
}

View File

@@ -1,101 +1,41 @@
'use strict'
const crypto = require('./webcrypto')()
const nodeify = require('nodeify')
const BN = require('asn1.js').bignum
const crypto = require('crypto')
const setImmediate = require('async/setImmediate')
const util = require('./util')
const toBase64 = util.toBase64
const toBn = util.toBn
const curves = {
'P-256': 'prime256v1',
'P-384': 'secp384r1',
'P-521': 'secp521r1'
}
exports.generateEphmeralKeyPair = function (curve, callback) {
nodeify(crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: curve
},
true,
['deriveBits']
).then((pair) => {
// forcePrivate is used for testing only
const genSharedKey = (theirPub, forcePrivate, cb) => {
if (!curves[curve]) {
return callback(new Error(`Unkown curve: ${curve}`))
}
const ecdh = crypto.createECDH(curves[curve])
ecdh.generateKeys()
setImmediate(() => callback(null, {
key: ecdh.getPublicKey(),
genSharedKey (theirPub, forcePrivate, cb) {
if (typeof forcePrivate === 'function') {
cb = forcePrivate
forcePrivate = undefined
forcePrivate = null
}
const privateKey = forcePrivate || pair.privateKey
nodeify(crypto.subtle.importKey(
'jwk',
unmarshalPublicKey(curve, theirPub),
{
name: 'ECDH',
namedCurve: curve
},
false,
[]
).then((publicKey) => {
return crypto.subtle.deriveBits(
{
name: 'ECDH',
namedCurve: curve,
public: publicKey
},
privateKey,
256
)
}).then((bits) => {
// return p.derive(pub.getPublic()).toBuffer('be')
return Buffer.from(bits)
}), cb)
if (forcePrivate) {
ecdh.setPrivateKey(forcePrivate.private)
}
let secret
try {
secret = ecdh.computeSecret(theirPub)
} catch (err) {
return cb(err)
}
setImmediate(() => cb(null, secret))
}
return crypto.subtle.exportKey(
'jwk',
pair.publicKey
).then((publicKey) => {
return {
key: marshalPublicKey(publicKey),
genSharedKey
}
})
}), callback)
}
const curveLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
// Marshal converts a jwk encodec ECDH public key into the
// form specified in section 4.3.6 of ANSI X9.62. (This is the format
// go-ipfs uses)
function marshalPublicKey (jwk) {
const byteLen = curveLengths[jwk.crv]
return Buffer.concat([
Buffer([4]), // uncompressed point
toBn(jwk.x).toBuffer('be', byteLen),
toBn(jwk.y).toBuffer('be', byteLen)
], 1 + byteLen * 2)
}
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve, key) {
const byteLen = curveLengths[curve]
if (!key.slice(0, 1).equals(Buffer([4]))) {
throw new Error('Invalid key format')
}
const x = new BN(key.slice(1, byteLen + 1))
const y = new BN(key.slice(1 + byteLen))
return {
kty: 'EC',
crv: curve,
x: toBase64(x),
y: toBase64(y),
ext: true
}
}))
}

119
src/crypto/rsa-browser.js Normal file
View 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
View 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')
}

View File

@@ -1,228 +1,80 @@
'use strict'
const nodeify = require('nodeify')
const asn1 = require('asn1.js')
// Node.js land
// First we look if node-webrypto-ossl is available
// otherwise we fall back to using keypair + node core
const util = require('./util')
const toBase64 = util.toBase64
const toBn = util.toBn
const crypto = require('./webcrypto')()
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)
let webcrypto
try {
webcrypto = require('node-webcrypto-ossl')
} catch (err) {
// not available, use the code below
}
// 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']
)
if (webcrypto && !process.env.NO_WEBCRYPTO) {
module.exports = require('./rsa-browser')
} else {
const crypto = require('crypto')
const keypair = require('keypair')
const setImmediate = require('async/setImmediate')
const pemToJwk = require('pem-jwk').pem2jwk
const jwkToPem = require('pem-jwk').jwk2pem
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.utils = require('./rsa-utils')
exports.getRandomValues = function (arr) {
return Buffer.from(crypto.getRandomValues(arr))
}
exports.generateKey = function (bits, callback) {
const done = (err, res) => setImmediate(() => {
callback(err, res)
})
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']
)
}
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')
let key
try {
key = keypair({
bits: bits
})
} catch (err) {
done(err)
return
}
}, 'der')
done(null, {
privateKey: pemToJwk(key.private),
publicKey: pemToJwk(key.public)
})
}
// Takes a jwk key
exports.unmarshalPrivateKey = function (key, callback) {
callback(null, {
privateKey: key,
publicKey: {
kty: key.kty,
n: key.n,
e: key.e
}
})
}
exports.getRandomValues = function (arr) {
return crypto.randomBytes(arr.length)
}
exports.hashAndSign = function (key, msg, callback) {
const sign = crypto.createSign('RSA-SHA256')
sign.update(msg)
setImmediate(() => {
callback(null, sign.sign(jwkToPem(key)))
})
}
exports.hashAndVerify = function (key, sig, msg, callback) {
const verify = crypto.createVerify('RSA-SHA256')
verify.update(msg)
setImmediate(() => {
callback(null, verify.verify(jwkToPem(key), sig))
})
}
}

View File

@@ -5,7 +5,7 @@ const BN = require('asn1.js').bignum
// Convert a BN.js instance to a base64 encoded string without padding
// Adapted from https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#appendix-C
exports.toBase64 = function toBase64 (bn) {
let s = bn.toBuffer('be').toString('base64')
let s = bn.toArrayLike(Buffer, 'be').toString('base64')
return s
.replace(/(=*)$/, '') // Remove any trailing '='s

View File

@@ -1,7 +1,11 @@
'use strict'
module.exports = function getWebCrypto () {
const WebCrypto = require('node-webcrypto-ossl')
const webCrypto = new WebCrypto()
return webCrypto
try {
const WebCrypto = require('node-webcrypto-ossl')
const webCrypto = new WebCrypto()
return webCrypto
} catch (err) {
// fallback to other things
}
}

View File

@@ -71,3 +71,12 @@ exports.marshalPrivateKey = (key, type) => {
return key.bytes
}
exports.randomBytes = (number) => {
if (!number || typeof number !== 'number') {
throw new Error('first argument must be a Number bigger than 0')
}
const buf = new Buffer(number)
c.rsa.getRandomValues(buf)
return buf
}

View File

@@ -17,7 +17,7 @@ class RsaPublicKey {
}
marshal () {
return crypto.jwkToPkix(this._key)
return crypto.utils.jwkToPkix(this._key)
}
get bytes () {
@@ -71,7 +71,7 @@ class RsaPrivateKey {
}
marshal () {
return crypto.jwkToPkcs1(this._key)
return crypto.utils.jwkToPkcs1(this._key)
}
get bytes () {
@@ -92,7 +92,7 @@ class RsaPrivateKey {
}
function unmarshalRsaPrivateKey (bytes, callback) {
const jwk = crypto.pkcs1ToJwk(bytes)
const jwk = crypto.utils.pkcs1ToJwk(bytes)
crypto.unmarshalPrivateKey(jwk, (err, keys) => {
if (err) {
return callback(err)
@@ -103,7 +103,7 @@ function unmarshalRsaPrivateKey (bytes, callback) {
}
function unmarshalRsaPublicKey (bytes) {
const jwk = crypto.pkixToJwk(bytes)
const jwk = crypto.utils.pkixToJwk(bytes)
return new RsaPublicKey(jwk)
}

View File

@@ -14,6 +14,11 @@ const lengths = {
'P-384': 97,
'P-521': 133
}
const secretLengths = {
'P-256': 32,
'P-384': 48,
'P-521': 66
}
describe('generateEphemeralKeyPair', () => {
curves.forEach((curve) => {
@@ -28,7 +33,7 @@ describe('generateEphemeralKeyPair', () => {
keys[0].genSharedKey(keys[1].key, (err, shared) => {
expect(err).to.not.exist
expect(shared).to.have.length(32)
expect(shared).to.have.length(secretLengths[curve])
done()
})
})
@@ -39,12 +44,29 @@ describe('generateEphemeralKeyPair', () => {
it('generates a shared secret', (done) => {
const curve = fixtures.curve
crypto.generateEphemeralKeyPair(curve, (err, alice) => {
parallel([
(cb) => crypto.generateEphemeralKeyPair(curve, cb),
(cb) => crypto.generateEphemeralKeyPair(curve, cb)
], (err, res) => {
expect(err).to.not.exist
const alice = res[0]
const bob = res[1]
bob.key = fixtures.bob.public
alice.genSharedKey(fixtures.bob.public, (err, s1) => {
parallel([
(cb) => alice.genSharedKey(bob.key, cb),
(cb) => bob.genSharedKey(alice.key, fixtures.bob, cb)
], (err, secrets) => {
expect(err).to.not.exist
expect(s1).to.have.length(32)
expect(
secrets[0]
).to.be.eql(
secrets[1]
)
expect(secrets[0]).to.have.length(32)
done()
})
})

View File

@@ -3,9 +3,9 @@
module.exports = {
curve: 'P-256',
bob: {
private: [
private: new Buffer([
181, 217, 162, 151, 225, 36, 53, 253, 107, 66, 27, 27, 232, 72, 0, 0, 103, 167, 84, 62, 203, 91, 97, 137, 131, 193, 230, 126, 98, 242, 216, 170
],
]),
public: new Buffer([
4, 53, 59, 128, 56, 162, 250, 72, 141, 206, 117, 232, 57, 96, 39, 39, 247, 7, 27, 57, 251, 232, 120, 186, 21, 239, 176, 139, 195, 129, 125, 85, 11, 188, 191, 32, 227, 0, 6, 163, 101, 68, 208, 1, 43, 131, 124, 112, 102, 91, 104, 79, 16, 119, 152, 208, 4, 147, 155, 83, 20, 146, 104, 55, 90
])

View File

@@ -97,5 +97,18 @@ describe('libp2p-crypto', () => {
true
)
})
it('randomBytes throws with no number passed', () => {
expect(() => {
crypto.randomBytes()
}).to.throw
})
it('randomBytes', () => {
const buf1 = crypto.randomBytes(10)
expect(buf1.length).to.equal(10)
const buf2 = crypto.randomBytes(10)
expect(buf1).to.not.eql(buf2)
})
})
})

21
test/util.spec.js Normal file
View File

@@ -0,0 +1,21 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const util = require('../src/crypto/util')
const BN = require('bn.js')
describe('Util', () => {
let bn
before((done) => {
bn = new BN('dead', 16)
done()
})
it('toBase64', (done) => {
expect(util.toBase64(bn)).to.be.eql('3q0')
done()
})
})