React Native 同步安全随机数生成

Posted

技术标签:

【中文标题】React Native 同步安全随机数生成【英文标题】:React Native Synchronous Secure Random Number Generation 【发布时间】:2016-04-16 09:20:19 【问题描述】:

我正在尝试在 React Native 项目中生成密钥对。密钥对生成工具依赖于crypto 模块的随机字节生成,它生成具有随机字节值的指定长度的缓冲区。

为了在 React Native 中使用 crypto 模块,它必须经过浏览器化,浏览器化的随机数生成器如下所示:

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 调试应用程序时,一切正常,但在 iosjavascriptCore 引擎上运行时,会调用 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,包括所有依赖于过去同步的方法的依赖项,现在不再同步。

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

或者,我尝试将它包装在一个方法中,该方法将设置一个信号量,调用异步生成器,并在一个 while 循环中等待信号量的值发生变化。该尝试失败,因为 while 循环阻止了回调的执行。这是我尝试的近似值,其中对 async 方法的调用已替换为 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

【问题讨论】:

【参考方案1】:

我找到了一个通常有效的答案。但是,它并不完美,因为它仅在应用启动期间不需要 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');
);

因此,我们在 React Native 中有一个同步的randomBytes 方法,前提是我们有机会在需要它的同步功能之前至少异步调用它一次。

【讨论】:

您重新定义randomBytes 的事实并不意味着使用它的决定 (crypto && crypto.getRandomValues) 会改变。那么你如何解决这个问题呢?为了通过该测试,我不愿意简单地定义crypto.getRandomValues,因为我不知道它还会影响什么。这就是我正在努力解决的问题:github.com/EOSIO/eosjs-keygen/issues/24【参考方案2】:

您的解决方案确实回答了这个问题,但似乎有点复杂。特别是,为什么不只使用 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');

【讨论】:

我相信 react-native-securerandom 在 2016 年 1 月还没有出现。它的第一次提交是 2017 年 10 月 :)

以上是关于React Native 同步安全随机数生成的主要内容,如果未能解决你的问题,请参考以下文章

Next.js/React 在组件中生成随机值时发出警告

React Native 在组件之间传递数组

React Native,在导航中将两个值传递到下一个屏幕

PHP 中的安全随机数生成

随机数生成器的 C++11 线程安全

多线程环境下生成随机数