2016-01-11 63 views
3

我试图在React Native项目中生成密钥对。密钥对生成工具依赖于crypto模块的随机字节生成,它会生成一个具有随机字节值的指定长度的缓冲区。React本机同步安全随机数生成

为了使用内无反应原住民的crypto模块,它必须browserified和browserified随机数生成器看起来是这样的:

https://github.com/crypto-browserify/randombytes/blob/master/browser.js

这里的关键组成部分:

var crypto = global.crypto || global.msCrypto 

if (crypto && crypto.getRandomValues) { 
    module.exports = randomBytes 
} else { 
    module.exports = oldBrowser 
} 

事实上,使用Chrome调试应用程序时,一切正常,但在iOS的JavaScriptCore引擎上运行时,将调用oldBrowser方法,出现以下错误:

secure random number generation not supported by this browser use chrome, FireFox or Internet Explorer 11

因此,我试图找到替代随机字节代。一个模块,我发现这是一个:

https://www.npmjs.com/package/react-native-randombytes

它使用设备的本地库来产生一个随机数,并公开其反应通过他们的OBJ-C/JS接口原住民。应该指出的是,这种方法只适用于iOS,而图书馆的作者还没有Android解决方案,但这是另一个问题。

该方法可以工作,因为它可以生成随机字节,但它有一个主要缺点。 React仅支持Objective-C和JavaScript之间的异步接口,这意味着此方法异步返回其结果。原来的randomBytes方法是同步的,几乎所有的SDK都依赖它同步使用它。因此,如果我们要使用异步版本,则必须重新编写所有SDK,包括依赖于以前同步且现在不再使用的方法的所有依赖项。

因此,我试图找到一种方法,使异步本机随机数生成器同步工作。有几个节点包可以做到这一点,其中最突出的一个是deasync,但deasync依赖于一些无法被浏览的核心节点模块,所以同步版本不起作用。

或者,我试着将它封装在一个方法中,该方法将设置一个信号量,调用异步生成器,并在while循环中等待信号量的值更改。该尝试失败,因为while循环阻止了执行的回调。下面是我的尝试的近似值,其中对异步方法的调用已被替换为setTimeout,并且要返回的随机数是四,由公平的掷骰子确定。

function testSynchronicity() { 
    var isDone = false; 
    setTimeout(function() { 
    isDone = true; 
    }, 1000); // set isDone to true after a second 

    while (!isDone) { 
    // do nothing 
    } 
    return 4; 
}; 

,因为这是不工作,我想我会完全尝试完全不同的随机数生成器,无需本地代码,依托react-native-randombytes模块,并与这一个对JavaScript去:

https://github.com/skeeto/rng-js

它在Node本身中工作正常,但在浏览它并尝试运行React Native内的第一个示例后,它抛出一个错误,指出主对象不是构造函数。这里是这个例子的样子:

var RNG = require('./rng_react'); // rng_react is rng-js browserified 
var rng = new RNG(); 
var randomValue = rng.random(0, 255, false); 

所以在这一点上,我有点失落,并希望有任何帮助。谢谢!

编辑:如果一切都失败了,就是这样,但我认为它几乎会打败问题的目的。 https://github.com/bitpay/bitcore-lib/blob/master/lib/crypto/random.js#L37

回答

5

我发现了一个通常有效的答案。但是,这是不完美的,因为只有在应用程序启动期间不需要randomBytes方法,它才有效。

我的解决方案的确使用了react-native-randombytes库。它依靠iOS的内置CSPRNG生成一个随机缓冲区,然后异步返回它。为了支持同步响应,我扩展了模块的randomBytes以在没有提供回调方法时不抛出错误,而是在调用它们时使用Stanford的JavaScript Crypto Library生成随机“单词”,将它们转换为缓冲区然后相应地修剪:

var sjcl = require('sjcl'); 
var sjclRandom = new sjcl.prng(10); 

var RNRandomBytes = require('react-native').NativeModules.RNRandomBytes; 

module.exports.randomBytes = function(length, cb) { 

    if (!cb) { 
    var size = length; 
    var wordCount = Math.ceil(size * 0.25); 
    var randomBytes = sjclRandom.randomWords(wordCount, 10); 
    var hexString = sjcl.codec.hex.fromBits(randomBytes); 
    hexString = hexString.substr(0, size * 2); 

    return new Buffer(hexString, 'hex'); 
    } 

    RNRandomBytes.randomBytes(length, function(err, base64String) { 
    if (err) { 
     cb(err); 
    } else { 
     cb(null, new Buffer(base64String, 'base64')); 
    } 
    }); 

}; 

的症结是,为了使SJCL库有足够的熵,它需要有正确播种。因此,在启动时,我们使用异步CSPRNG功能播种SJCL随机数生成器:

module.exports.randomBytes(4096, function(err, buffer) { 
    var hexString = buffer.toString('hex'); 
    // we need to convert the hex string to bytes, or else SJCL assumes low entropy 
    var stanfordSeed = sjcl.codec.hex.toBits(hexString); 
    sjclRandom.addEntropy(stanfordSeed, 10, 'csprng'); 
}); 

因此,我们有内同步randomBytes方法作出反应原住民,只要我们有机会至少异步调用它一次在我们需要它的同步功能之前。

0

您的解决方案确实回答了问题,但看起来有点复杂。特别是,为什么不使用SJCL?

在我的情况下,我已经结束了使用react-native-securerandom,这只是Android和iOS本机调用的一个薄包装。然后我已经完成了初始化SJCL的RNG:

const { generateSecureRandom } = require('react-native-securerandom'); 
const sjcl = require('lib/vendor/sjcl'); 

const randomBytes = await generateSecureRandom(1024/8); 

let temp = []; 
for (let n in randomBytes) { 
    if (!randomBytes.hasOwnProperty(n)) continue; 
    temp.push(randomBytes[n].toString(16)); 
} 

const hexSeed = sjcl.codec.hex.toBits(temp.join('')); 
sjcl.random.addEntropy(hexSeed, 1024, 'generateSecureRandom');