2016-01-11 65 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');