browserify / crypto-browserify

partial implementation of node's `crypto` for the browser

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Performance issue when running standalone

clauderobi opened this issue · comments

I am developing a react-native application.

When running with the react-native-debugger, performance is adequate. A RSA decryption, using a 4096 bit key, takes approx 350msec on the Android simulator. Using the same simulator but disabling remote debugging, the same decryption takes 15sec. This is 45x increase in processing time. Needless to say that the app is very very very slow...

I also noticed that window.crypto.subtle is undefined when running without the debugger.

Clearly, there is an environment difference. But what it is? And how to debug this?

I am open to any suggestions!

window.crypto isn’t this package, that’s web crypto. Your problem doesn’t sound related to this package.

I understand that crypto-browserify is not using window.crypto but I suspect that something is polyfilling the environment in some way that helps crypto-browserify. My comment about window.crypto.subtle is just a minor symptom.

In any case, the call that is slow is definitely crypto-browserify.privateDecrypt(xxx). (And other crypto related things).

BTW, I just tested a on a real device and the phenomenon is identical.

crypto-browserify is meant to be a polyfill for node's crypto module, not for web crypto, so i don't see how it could be relevant. Can you elaborate on what exact code you're invoking that's slow?

This is my function that initiates a decryption

import Crypto from 'crypto-browserify';

export async function decryptRSA(data, key, hash) {
  try {
    let option = {
      key: key,
      padding: Crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: 'sha1'
    };
    if (hash === 'sha256') {
      option.oaepHash = 'sha256';
    }
    
    //log('Before Crypto.privateDecrypt');
    let result = await Crypto.privateDecrypt(option, Buffer.from(b64ToUint8(data)))
    return result;
  } catch(error) {
    log ('Failed to decrypt using RSA (crypto-browserify)- ' + error.message)
    throw error;
  }  
}

It takes 15sec on the simulator and 45sec on my Pixel 3a to return (and just 345msec with the debugger).

For info (from package.json):
"crypto-browserify": "^3.12.0",

There is the call to b64ToUint8 from a private library that uses atob but I would be surprise that it is the culprit.

Thanks, that's helpful.

It would make sense that decryption would be much slower when there's no native crypto available - however, I'm not sure why it would be available when debugging and not otherwise.

https://github.com/webview-crypto/react-native-webview-crypto may be relevant?

Interesting concept webview-crypto. IIUC, this simply replaces crypto-browserify with something else (the actual browser engine which is good, particularly in the context of cryptography).

But before trying this, I wanted to work harder (I sound like George Orwell here... ) and dive very deep. I still did not find the problem yet but it is in the bn.js module. For unknown reason, the call to redPoW (from crt, which is called by privateDecrypt) is much longer in standalone than with the debugger context.

I am guessing bn stands for big number since the function in there are math operation (sqr, mul, shift, etc.)

Need to dive deeper....

Well, my final conclusion, but correct me if I am wrong, is that the crypto-browserify uses Javascript code to handle the actual encryption / decryption (math operation) and therefore is too slow for real life utilization. 45seconds to decrypt an RSA message (with a key size of 4096 bits) is simply too long.

The better solution, so far, is https://github.com/webview-crypto/react-native-webview-crypto

I did try other solutions, such as react-native-fast-rsa but it is incompatible with openSSL (at least when using the RSA-OAEP padding scheme); in other words, it is probably bugger when it comes to setup the
parameters.

Makes sense. It's likely that it's fast enough in general, but not inside a react native webview.