isomorphic-webcrypto icon indicating copy to clipboard operation
isomorphic-webcrypto copied to clipboard

RSA generatekey, unsupported algorithm

Open davidcallanan opened this issue 3 years ago • 20 comments

This is literally the only package I have found that supports webcrypto with react native...

But I really need to be able to generate the following RSA key (for compatibility with the rest of our system)...

await crypto.subtle.generateKey(
    {
      name: "RSA-PSS",
      hash: "SHA-256",
      modulusLength: 4096,
      publicExponent: new Uint8Array([1, 0, 1]),
    },
    true,
    ["sign", "verify"],
  );

Any plans to support this? I would be really appreciative.

davidcallanan avatar Aug 07 '20 19:08 davidcallanan

The react native implementation of WebCrypto is in js, so generating an RSA key would be remarkably slow. The original version of msrCrypto didn't support this, but perhaps the latest version does. I intend to integrate the latest version at some point (no timeline), but you're welcome to test it: https://github.com/microsoft/MSR-JavaScript-Crypto.

kevlened avatar Aug 07 '20 19:08 kevlened

If the latest supports it I will definitely test it :)

Even if it takes 20 or 30 seconds, if I generate it the second the app launches and the user doesn't make any action that requires it for that time, it is ok, and I will also be caching the result in localstorage.

davidcallanan avatar Aug 07 '20 19:08 davidcallanan

Ah, I see. Because it's all in js, you'll lock RN's js thread for that time. The app would basically freeze. That said, there may be a workaround, but I haven't investigated.

As for the latest msrCrypto, after a brief glance, it appears to support generating RSA keys, but I haven't tried it. If you do, lmk.

kevlened avatar Aug 07 '20 19:08 kevlened

The javascript appears to run in a worker, so shouldn't hang the main thread. But I'm having no luck getting the code to run in react native.

davidcallanan avatar Aug 07 '20 20:08 davidcallanan

RN doesn’t support workers, so you have to hardcode it to work in a single thread (that’s how I modified the old msrCrypto). I’d test it in a browser. If it works in a browser, I’ll modify it to work in RN.

On Fri, Aug 7, 2020 at 16:20 David Callanan [email protected] wrote:

The javascript appears to run in a worker, so shouldn't hang the main thread. But I'm having no luck getting the code to run in react native.

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/kevlened/isomorphic-webcrypto/issues/34#issuecomment-670697166, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHJHMDRRF7C4IBFE6BTC3DR7RO2VANCNFSM4PX5H6RA .

kevlened avatar Aug 07 '20 20:08 kevlened

Not looking promising, it's hung my chrome window, no results after a few minutes.

davidcallanan avatar Aug 07 '20 20:08 davidcallanan

I hope this method of generation would be implemented soon. It would be really helpful in my project to have full WebCrypto support.

cryptoAlgorithm avatar Jul 03 '21 13:07 cryptoAlgorithm

@cryptoAlgorithm If I remember correctly, in the end I just created a rest api for this and ran the crypto code on the backend. Not the best solution, but might be a hackish option for the time being.

davidcallanan avatar Jul 03 '21 13:07 davidcallanan

Hmm i guess i could do that, but the entire reason i wrote the app in React Native (other than being cross platform) was that i could mostly reuse code from our web client which is also written in React. Unfortunately, there aren't libraries that support this RSA algorithm, which is a bit disappointing.

cryptoAlgorithm avatar Jul 03 '21 14:07 cryptoAlgorithm

It’s possible to generate these keys in a WebView. The catch is the WebView must be in the render tree (it can be hidden though). Here’s an implementation that renders a hidden webview and proxies WebCrypto calls: https://github.com/webview-crypto/react-native-webview-crypto

kevlened avatar Jul 03 '21 14:07 kevlened

Yeah but if i understand correctly the key generation will still be running in JavaScript but not natively right(?) If thats the case, what's the difference between running it in react native itself?

cryptoAlgorithm avatar Jul 03 '21 14:07 cryptoAlgorithm

Regarding that library, that might help with my issue. I'll give it a try right now

cryptoAlgorithm avatar Jul 03 '21 14:07 cryptoAlgorithm

In browsers, WebCrypto is implemented in native code, you just access it with js. The performance is significantly better.

In React Native, all js is run on the main thread. That means even if an implementation could generate a key in 5 seconds, the UI would freeze for 5 seconds. In addition to faster generation, the proxy method offloads the work from the main thread to the WebView, so your UI remains responsive.

kevlened avatar Jul 03 '21 15:07 kevlened

Yeah I made a mistake in one of my comments. I commented before looking at the library, and assumed that they were running a JS implimentation of webcrypto in a WebView, which I found rather meaningless. Turns out they were using the native browser implimentation. Although now that I've added the libraries, my app no longer compiles for some duplicated method/symbol error...

cryptoAlgorithm avatar Jul 03 '21 16:07 cryptoAlgorithm

@kevlened That's a genius idea to use a WebView

davidcallanan avatar Jul 04 '21 12:07 davidcallanan

@cryptoAlgorithm

Hmm i guess i could do that, but the entire reason i wrote the app in React Native (other than being cross platform) was that i could mostly reuse code from our web client which is also written in React.

This is a big problem I see all the time. For one of my recent projects I decided to obtain all dependencies through dependency injection (passing in dependencies into functions) and I used factory functions to abstract away implementation details of certain dependencies. I refused to ever import a dependency directly (like a singleton).

With that in place, 90% of my code was reusable. I was able to switch my entire frontend to React Native in a day without needing to rewrite the majority of my core logic. (Obviously the UI part was not reusable). For any libraries that were not available in React Native (such as cryptography or fetch api), I would just dependency-inject an alternative library.

When I failed to find a webcrypto implementation, I just quickly wrote a hackish implementation that communicated with my backend to do it, and I didn't have to change any other code in my project. Obviously only a short-term solution, but I think it is very important to organize your code in a way that allows you to easily plug in and out different implementations of dependencies.

(Sorry this is just me ranting about architecture, feel free to ignore this message).

davidcallanan avatar Jul 04 '21 13:07 davidcallanan

@davidcallanan that seems like a very interesting approach... Might try it with a future project. But if the RSA keypair is generated in the backend, there are so many things that can go wrong. Like man in the middle attacks, backend vulnerabilities etc. Even if everything could be 100% secure you no longer have truly end to end encryption since the key originates from your server. That's one of the shortcomings that came to my mind when you mentioned this hackish method. (Not trying to be negative or anything, just trying to point out potential security flaws)

cryptoAlgorithm avatar Jul 04 '21 16:07 cryptoAlgorithm

@cryptoAlgorithm This idea with the backend is only supposed to be a temporary solution until a better one arises. I was mostly trying to show my approach for code re-use and how you should be able to switch between different solutions as they come to being without sacrificing code re-use. I definitely agree that using a backend defeats the purpose of end-to-end encryption. (In my case I wasn't using it for end-to-end encryption so it didn't affect me).

davidcallanan avatar Jul 04 '21 17:07 davidcallanan

@cryptoAlgorithm @davidcallanan The recommended library runs code in the WebView without hitting a remote server. Here's the code for the suggested library (basically loads an empty html file, then injects js that runs client side). The WebView method is more secure than the js version today, because it's built on top of the platform's native crypto APIs.

There is one real limitation to any polyfill I've seen in React Native: non-exportable keys. In a browser, you can generate key pairs where the private portion can't be serialized to a jwk or pem. This prevents an xss from exfiltrating a private key. In the browser, not being able to serialize the key means you have to store the key in IndexedDB if you want to use it in future sessions (IndexedDB can store some objects without serializing them). There is no way to simulate the functionality in React Native unless you use a WebCrypto polyfill built on top of the iOS and Android crypto primitives.

The WebView method is certainly the most secure, reliable, and up-to-date method. I've considered moving this library to use the WebView method by default. The only caveat is the extra step of including the WebView in the render tree. This extra step just becomes cumbersome if you're shipping a library built on top of isomorphic-webcrypto to end-users.

Hope that helps with your decision.

kevlened avatar Jul 04 '21 17:07 kevlened

@kevlened, I've ran into some issues with this WebView WebCrypto approach, namely the fact that Safari on iOS doesn't fully support RSA-OEAP encryption/decryption with SHA-512/SHA-256 hashes. Only SHA-1 is supported, which won't do. I look forward to the day when Safari finally decides to fix this (its a bug that has been around for ages), but for now I can't really use this approach.

cryptoAlgorithm avatar Jul 05 '21 10:07 cryptoAlgorithm