This repository has been archived by the owner on Jul 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: crypto in insecure browser context
This PR adds `crypto-browserify` to the dependencies and replaces `crypto` with `crypto-browserify` when bundled in the browser. In files that require webcrypto we check to see if it's available. If it is not we require the Node.js implementation (which has `crypto` replaced with `crypto-browserify`) and if it is available then we use the webcrypto version (so we get fast crypto). Shipping `crypto-browserify` adds to the bundle size: Current gzipped size: 142,824 bytes New gzipped size: 214,499 bytes Difference: **+71,675 bytes** It's not an insignificant addition so we need to decide whether this is worth it. If not accepted, we need to add checks when libp2p-crypto methods are called and callback with an appropriate error message. JS IPFS will continue to have issues opened with confusion around this otherwise! See ipfs/js-ipfs#963 ipfs/js-ipfs#964 ipfs/js-ipfs#2153 resolves #105 License: MIT Signed-off-by: Alan Shaw <[email protected]>
- Loading branch information
Alan Shaw
committed
Jul 4, 2019
1 parent
0ffe318
commit 92c78f4
Showing
15 changed files
with
177 additions
and
225 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,8 @@ | |
"main": "src/index.js", | ||
"leadMaintainer": "Friedel Ziegelmayer <[email protected]>", | ||
"browser": { | ||
"./src/hmac/index.js": "./src/hmac/index-browser.js", | ||
"./src/keys/ecdh.js": "./src/keys/ecdh-browser.js", | ||
"./src/aes/ciphers.js": "./src/aes/ciphers-browser.js", | ||
"./src/keys/rsa.js": "./src/keys/rsa-browser.js" | ||
"crypto": "crypto-browserify", | ||
"./src/keys/keypair.js": "./src/keys/keypair-browser.js" | ||
}, | ||
"files": [ | ||
"src", | ||
|
@@ -35,25 +33,23 @@ | |
], | ||
"license": "MIT", | ||
"dependencies": { | ||
"asmcrypto.js": "^2.3.2", | ||
"asn1.js": "^5.0.1", | ||
"async": "^2.6.2", | ||
"bn.js": "^4.11.8", | ||
"browserify-aes": "^1.2.0", | ||
"bs58": "^4.0.1", | ||
"crypto-browserify": "^3.12.0", | ||
"iso-random-stream": "^1.1.0", | ||
"keypair": "^1.0.1", | ||
"libp2p-crypto-secp256k1": "~0.3.0", | ||
"multihashing-async": "~0.6.0", | ||
"node-forge": "~0.7.6", | ||
"pem-jwk": "^2.0.0", | ||
"protons": "^1.0.1", | ||
"rsa-pem-to-jwk": "^1.1.3", | ||
"tweetnacl": "^1.0.1", | ||
"ursa-optional": "~0.9.10" | ||
}, | ||
"devDependencies": { | ||
"aegir": "^18.2.2", | ||
"bn.js": "^4.11.8", | ||
"benchmark": "^2.1.4", | ||
"bundlesize": "~0.17.1", | ||
"chai": "^4.2.0", | ||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict' | ||
|
||
const crypto = require('crypto') | ||
const lengths = require('./lengths') | ||
const nextTick = require('async/nextTick') | ||
|
||
exports.create = function (hash, secret, callback) { | ||
const res = { | ||
digest (data, cb) { | ||
const hmac = crypto.createHmac(hash.toLowerCase(), secret) | ||
|
||
hmac.update(data) | ||
|
||
nextTick(() => { | ||
cb(null, hmac.digest()) | ||
}) | ||
}, | ||
length: lengths[hash] | ||
} | ||
|
||
callback(null, res) | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,5 @@ | ||
'use strict' | ||
|
||
const crypto = require('crypto') | ||
const lengths = require('./lengths') | ||
const nextTick = require('async/nextTick') | ||
const webcrypto = require('../webcrypto') | ||
|
||
exports.create = function (hash, secret, callback) { | ||
const res = { | ||
digest (data, cb) { | ||
const hmac = crypto.createHmac(hash.toLowerCase(), secret) | ||
|
||
hmac.update(data) | ||
|
||
nextTick(() => { | ||
cb(null, hmac.digest()) | ||
}) | ||
}, | ||
length: lengths[hash] | ||
} | ||
|
||
callback(null, res) | ||
} | ||
module.exports = webcrypto ? require('./index-webcrypto') : require('./index-crypto') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
'use strict' | ||
|
||
const crypto = require('crypto') | ||
const nextTick = require('async/nextTick') | ||
|
||
const curves = { | ||
'P-256': 'prime256v1', | ||
'P-384': 'secp384r1', | ||
'P-521': 'secp521r1' | ||
} | ||
|
||
exports.generateEphmeralKeyPair = function (curve, callback) { | ||
if (!curves[curve]) { | ||
return callback(new Error(`Unkown curve: ${curve}`)) | ||
} | ||
const ecdh = crypto.createECDH(curves[curve]) | ||
ecdh.generateKeys() | ||
|
||
nextTick(() => callback(null, { | ||
key: ecdh.getPublicKey(), | ||
genSharedKey (theirPub, forcePrivate, cb) { | ||
if (typeof forcePrivate === 'function') { | ||
cb = forcePrivate | ||
forcePrivate = null | ||
} | ||
|
||
if (forcePrivate) { | ||
ecdh.setPrivateKey(forcePrivate.private) | ||
} | ||
|
||
let secret | ||
try { | ||
secret = ecdh.computeSecret(theirPub) | ||
} catch (err) { | ||
return cb(err) | ||
} | ||
|
||
nextTick(() => cb(null, secret)) | ||
} | ||
})) | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,5 @@ | ||
'use strict' | ||
|
||
const crypto = require('crypto') | ||
const nextTick = require('async/nextTick') | ||
const webcrypto = require('../webcrypto') | ||
|
||
const curves = { | ||
'P-256': 'prime256v1', | ||
'P-384': 'secp384r1', | ||
'P-521': 'secp521r1' | ||
} | ||
|
||
exports.generateEphmeralKeyPair = function (curve, callback) { | ||
if (!curves[curve]) { | ||
return callback(new Error(`Unkown curve: ${curve}`)) | ||
} | ||
const ecdh = crypto.createECDH(curves[curve]) | ||
ecdh.generateKeys() | ||
|
||
nextTick(() => callback(null, { | ||
key: ecdh.getPublicKey(), | ||
genSharedKey (theirPub, forcePrivate, cb) { | ||
if (typeof forcePrivate === 'function') { | ||
cb = forcePrivate | ||
forcePrivate = null | ||
} | ||
|
||
if (forcePrivate) { | ||
ecdh.setPrivateKey(forcePrivate.private) | ||
} | ||
|
||
let secret | ||
try { | ||
secret = ecdh.computeSecret(theirPub) | ||
} catch (err) { | ||
return cb(err) | ||
} | ||
|
||
nextTick(() => cb(null, secret)) | ||
} | ||
})) | ||
} | ||
module.exports = webcrypto ? require('./ecdh-webcrypto') : require('./ecdh-crypto') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('keypair') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
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') | ||
} | ||
|
||
module.exports = keypair |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
'use strict' | ||
|
||
const crypto = require('crypto') | ||
const randomBytes = require('../random-bytes') | ||
const nextTick = require('async/nextTick') | ||
const keypair = require('./keypair') | ||
const pemToJwk = require('pem-jwk').pem2jwk | ||
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) | ||
}) | ||
} | ||
|
||
// Takes a jwk key | ||
exports.unmarshalPrivateKey = function (key, callback) { | ||
nextTick(() => { | ||
if (!key) { | ||
return callback(new Error('Key is invalid')) | ||
} | ||
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.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) | ||
}) | ||
} |
File renamed without changes.
Oops, something went wrong.