我正在尝试在React Native项目中生成密钥对.密钥对生成工具依赖于crypto
模块的随机字节生成,它生成具有随机字节值的指定长度的缓冲区.
为了crypto
在React Native中使用该模块,必须对其进行浏览,并且浏览器化的随机数生成器如下所示:
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
方法会被调用,引发以下错误:
此浏览器不支持的安全随机数生成使用chrome,FireFox或Internet Explorer 11
因此,我试图找到随机字节生成的替代品.我发现的一个模块就是这个模块:
https://www.npmjs.com/package/react-native-randombytes
它使用设备的本机库生成随机数,并通过其Obj-C/JS接口将其公开给React Native.应该注意的是,这种方法仅适用于iOS,而且该库的作者还没有Android解决方案,但这是另一个问题.
这种方法有效,因为它可以生成随机字节,但它有一个主要缺点.React仅支持Objective-C和JavaScript之间的异步接口,这意味着此方法异步返回其结果.原始randomBytes
方法是同步的,几乎每个依赖它的SDK都会同步使用它.因此,如果我们使用异步版本,则必须为其重写所有SDK,包括依赖于曾经是同步的方法的所有依赖项,现在将不再是.
因此,我试图找到一种方法使异步本机随机数生成器同步工作.有几个节点包可以做到这一点,其中最突出的一个是deasync
,但deasync
依赖于一些无法浏览化的核心节点模块,因此同步版本不起作用.
或者,我尝试将其包装在一个方法中,该方法将设置信号量,调用异步生成器,并在while循环中等待信号量值的更改.该尝试失败,因为while循环阻止回调执行.这是我的尝试的近似值,其中异步方法的调用已被a替换setTimeout
,并且要返回的随机数是4,由公平骰子滚动确定.
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
我找到了一个通常有效的答案.但是,它并不完美,因为只有randomBytes
在应用程序启动期间不需要该方法时它才有效.
我的解决方案确实涉及使用react-native-randombytes
库.它依靠iOS的内置CSPRNG来生成随机缓冲区,然后异步返回它.为了支持同步响应,我扩展了模块,randomBytes
以便在没有提供回调方法时抛出错误,而是使用斯坦福的JavaScript加密库生成随机"单词",因为它们被调用,将它们转换为缓冲区和然后修剪它:
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
在React Native中有一个同步方法,只要我们有机会在需要其同步功能之前至少异步调用一次.