Skip to content
This repository has been archived by the owner on Sep 13, 2024. It is now read-only.

Commit

Permalink
Allow React Native use without ejecting
Browse files Browse the repository at this point in the history
  • Loading branch information
kevlened committed Feb 3, 2018
1 parent 8d041b9 commit a17a553
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 36 deletions.
29 changes: 3 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ webcrypto library for Node, React Native and IE11+

## What?

There's a great Node polyfill for the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API), but [it's not isomorphic yet](https://github.com/anvilresearch/webcrypto/issues/57). This fills the gap until it is.
There's a great Node polyfill for the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API), but [it's not isomorphic](https://github.com/anvilresearch/webcrypto/issues/57).

IE11 and versions of Safari < 11 use an older version of the spec, so the browser implementation includes a [webcrypto-shim](https://github.com/vibornoff/webcrypto-shim) to iron out the differences. You'll still need to provide your own Promise polyfill.

Expand Down Expand Up @@ -42,41 +42,18 @@ crypto.subtle.digest(
* Node 4+
* React Native

### Other Environments

If you need to support other environments (like older browsers), use the [Microsoft Research library](https://github.com/kevlened/msrCrypto).

```javascript
const crypto = require('msrcrypto')

/**
* IMPORTANT: On platforms without crypto, the
* js-only implementation needs another source
* of entropy for operations that require
* random numbers (creating keys, encrypting,
* wrapping keys) This should NOT be Math.random()
*/

crypto.initPrng(randomArrayOf48Bytes)
```

### React Native

React Native support is implemented using [the Microsoft Research library](https://github.com/kevlened/msrCrypto). The React Native environment only supports `Math.random()`, so [react-native-securerandom](https://github.com/rh389/react-native-securerandom) is used to provide proper entropy. This is handled automatically, except for `crypto.getRandomValues()`, which requires you wait:

```javascript
const crypto = require('isomorphic-webcrypto')

crypto.generateKey() // safe (all other methods are safe)
crypto.getRandomValues() // insecure!!!

// Only needed for crypto.getRandomValues
crypto.ensureSecure(err => {
if (err) throw err
crypto.getRandomValues() // safe

const safeValues = crypto.getRandomValues();
// Only wait once, future calls are secure
// No need to wrap every getRandomValues call
})
```

Expand All @@ -92,4 +69,4 @@ You should use [the webcrypto-shim](https://github.com/vibornoff/webcrypto-shim)

## License

MIT
MIT
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "isomorphic-webcrypto",
"version": "1.3.1",
"version": "1.3.0",
"description": "webcrypto library for Node, React Native and IE11+",
"main": "./src/main.js",
"module": "./src/index.mjs",
Expand Down Expand Up @@ -37,10 +37,8 @@
"b64u-lite": "^1.0.1",
"mitt": "^1.1.3",
"msrcrypto": "^1.4.0",
"react-native-securerandom": "^0.1.1",
"str2buf": "^1.2.0",
"webcrypto-shim": "^0.1.2"
},
"peerDependencies": {
"react-native-securerandom": "^0.1.1"
}
}
54 changes: 48 additions & 6 deletions src/react-native.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
const generateSecureRandom = require('react-native-securerandom').generateSecureRandom
let generateSecureRandom;
if (require.getModules) {
const NativeModules = require('react-native').NativeModules;
const RNSecureRandom = NativeModules.RNSecureRandom;
if (RNSecureRandom && RNSecureRandom.generateSecureRandomAsBase64) {
generateSecureRandom = require('react-native-securerandom').generateSecureRandom;
}
}

if (!generateSecureRandom) {
console.log(`
isomorphic-webcrypto cannot ensure the security of some operations.
Please eject and run:
npm install react-native-securerandom --save
react-native link
If you'd like not to eject, upvote this feature request:
https://expo.canny.io/feature-requests/p/crypto-api
`);
generateSecureRandom = function(length) {
const uint8Array = new Uint8Array(length);
while (length && length--) {
uint8Array[length] = Math.floor(Math.random() * 256);
}
return Promise.resolve(uint8Array);
}
}

const EventEmitter = require('mitt')
const b64u = require('b64u-lite')
const str2buf = require('str2buf')
Expand Down Expand Up @@ -29,11 +57,25 @@ crypto.ensureSecure = function(cb) {
secureWatch.on('secureRandomError', () => cb(secureRandomError))
}

function standardAlgoName(algo) {
function standardizeAlgoName(algo) {
const upper = algo.toUpperCase();
return upper === 'RSASSA-PKCS1-V1_5' ? 'RSASSA-PKCS1-v1_5' : upper;
}

const originalGetRandomValues = crypto.getRandomValues;
crypto.getRandomValues = function getRandomValues() {
if (!secured) {
throw new Error(`
You must wait until the library is secure to call this method:
crypto.ensureSecure(err => {
if (err) throw err;
const safeValues = crypto.getRandomValues();
});
`);
}
return originalGetRandomValues.apply(crypto, arguments);
}

// wrap all methods to ensure they're secure
const methods = [
'decrypt',
Expand Down Expand Up @@ -72,12 +114,12 @@ crypto.subtle.generateKey = function() {
.then(res => {
if (res.publicKey) {
res.publicKey.usages = ['verify'];
res.publicKey.algorithm.name = standardAlgoName(res.publicKey.algorithm.name);
res.publicKey.algorithm.name = standardizeAlgoName(res.publicKey.algorithm.name);
res.privateKey.usages = ['sign'];
res.privateKey.algorithm.name = standardAlgoName(res.privateKey.algorithm.name);
res.privateKey.algorithm.name = standardizeAlgoName(res.privateKey.algorithm.name);
} else {
res.usages = ['sign', 'verify'];
res.algorithm.name = standardAlgoName(res.algorithm.name);
res.algorithm.name = standardizeAlgoName(res.algorithm.name);
}
return res;
});
Expand All @@ -89,7 +131,7 @@ crypto.subtle.importKey = function() {
const key = arguments[1];
return originalImportKey.apply(this, arguments)
.then(res => {
res.algorithm.name = standardAlgoName(res.algorithm.name);
res.algorithm.name = standardizeAlgoName(res.algorithm.name);
switch(res.type) {
case 'secret':
res.usages = ['sign', 'verify'];
Expand Down

0 comments on commit a17a553

Please sign in to comment.