-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Specification
The work in #155 involving nativescript meant that we are starting to consider alternatives to Node forge crypto in order to standardise our crypto API and future proof to future JS-based platforms. There are number of reasons to look into webcrypto:
- WebCrypto is a standard across ES platforms, thus enabling more potential native-implementations which can improve performance and security (prevent timing attacks)
- WebCrypto API focuses on using ES-compliant buffers like
Uint8Array
andArrayBuffer
which can help us standardise our buffer usage across js-db, js-id, js-workers and more, especially as workers requireArrayBuffer
to do zero-copy - There is existing work with WebCrypto API involving WASM to plug in functionality that isn't supported by the standard, such as providing ed25519 keys, and this will help us resolve the usage of ed25519 Replace node-forge RSA Keypair With ed25519/x25519 Keypair #168
- The
node-forge
source code isn't well maintained and doesn't have as many eyes watching and evaluating its security
Now for some background:
This comment #43 (comment) explains how we came to be using node-forge
as opposed to other cryptographic libraries.
I know that when Polykey project first started, we initially were thinking of using PGP and thus the kbpgp.js library (https://github.com/keybase/kbpgp). We ended up going away from PGP due to its limited usage in a number of scenarios that we want PK to deal with. Namely end to end encrypted network communication which is a TLS issue, that makes use of X.509 certificates rather than PGP certificates. Furthermore we also had symmetric encryption/decryption scenarios like js-encryptedfs that again would not make use of PGP standards. Therefore it just lacked interoperability with many other cryptographic scenarios, it seemed like its own island of standards, the library can still be brought back in in the future if we find usecases for PK using PGP.
However in choosing node-forge, we came across a few other problems. Mainly overall-cross platform compatibility planning for mobile devices. This is not just a problem with crypto, but also other libraries that are used in our networking
domain such as utp-native.
Here are something I found that may be relevant to us proceeding here:
- The webcrypto standard (https://w3c.github.io/webcrypto/) is now the official standard for cryptographic operations in browser environments. It is now being supported by all major browsers and electron
- This webcrypto standard is now taking over other deployment platforms such as in Nodejs: https://nodejs.org/api/webcrypto.html & https://www.nearform.com/blog/implementing-the-web-cryptography-api-for-node-js-core/
- As a standardised API, switching over to this API gives us more cross-platform opportunity as the rest of the world's development ecosystem catches up and migrates over to webcrypto standard.
- In particular are nativescript and react-native ecosystems. Currently none of them have official crypto APIs, they expect the developer to use underlying native iOS or Android crypto APIs.
- However I found out that the GUN project https://github.com/amark/gun#additional-cryptography-libraries claims to be able to use webcrypto on react-native and other platforms.
- It does this through a "webview" trick. Basically this hooks into the browser runtimes that are on iOS and Android to perform the actual crypto and then return the results back to the main application. I have no idea about the performance characteristics of this trick. This trick is described here: https://gun.eco/docs/React-Native and https://github.com/webview-crypto/react-native-webview-crypto
- The usage of webcrypto libraries is pioneered by "PeculiarVentures" which has these main libraries:
- https://github.com/PeculiarVentures/PKI.js - this could be an alternative to node-forge for all of our PKI/X.509 and TLS related functionality (previously it was claimed this was overly complex compared to
node-forge
) - https://github.com/PeculiarVentures/webcrypto - this is a generic polyfill for webcrypto, not entirely sure how it wraps the native webcrypto inside nodejs or if smooths over the differences, there is a discussion about this library in relation to other webcrypto polyfills targeting nodejs https://github.com/PeculiarVentures/webcrypto, because this is also mentioned with respect to the webview trick, there may also be a relationship between the webview trick and this polyfill
- They have many other crypto related libraries that we should investigate
- https://github.com/PeculiarVentures/PKI.js - this could be an alternative to node-forge for all of our PKI/X.509 and TLS related functionality (previously it was claimed this was overly complex compared to
All of this will mean that we either replace node-forge, or end up creating a adapter pattern where we plugin different crypto implementions depending on our environment. At this point in time, the keys
domain abstracts over most(all?) crypto operations for all other domains. Except in the case of EFS which is currently pinned to node-forge
(it may be a good idea to abstract that and expect an interface of functions for EFS).
Cross platform compatibility here isn't just about the fundamental crypto library. It's also about other parts of PK. One closely related situation is the JOSE libraries. As they involve cryptographic operations, they currently seem to "fix" their underlying crypto library as well. It would be ideal that if we standardise on a crypto library for cross-platform deployment, that we can also ensure that our JOSE library is using the same crypto library to reduce our crypto attack surface. We are currently using https://github.com/panva/jose which uses native crypto depending on the platform including webcrypto. Contenders include https://github.com/cisco/node-jose (which fixes on node-forge) and https://github.com/square/js-jose.
Additional context
- Make this workable ES-compliant platforms (like browsers) by generalising crypto and performance APIs js-id#2 - js-id also should be using WebCrypto
- React Native and Mobile OS (iOS and Android) Compatibility #155 - will impact NativeScript deployment
- Use
bufferWrap
to supportArrayBuffer
,Uint8Array
andBuffer
js-db#3 - can help make use of the migration toArrayBuffer
and typed arrays - WebAssembly resources
- There are 2 well supported runtimes for WASM:
- wasm3 - supports interpretation
- wasmer - supports JIT and AOT compilation
- https://www.fastly.com/blog/standard-cryptography-api-webassembly
- https://github.com/WebAssembly/wasi-crypto
- https://stackoverflow.com/questions/48891593/webcryptoapi-vs-webassembly-encryption-module
- https://medium.com/nexenio/a-random-story-on-webcrypto-and-webassembly-6f9e00c73a - This describes how to use webcrypto together with webassembly when you need a custom crytographic functionality not supported inside webcrypto.
- https://medium.com/cubbit/how-to-build-a-crypto-isomorphic-library-with-javascript-and-webassembly-6fc7aa708437
- https://github.com/cubbit/enigma and WASM in Enigma cubbit/enigma#16
- There are 2 well supported runtimes for WASM:
Wasmer can compile WASM code to native code. But wasm3 is for interpretation. Why use interpetation?
It appears that in some cases interpretation can be more widely deployed. There are examples of iOS apps using wasm3. https://github.com/kateinoigakukun/wasmic-ios
It's becoming fast a standard target for many languages. Even TypeScript when ported to AssemblyScript can be compiled to WASM.
Once it is WASM, the only thing missing is broad adoption of WASI. If WASI is broadly adopted like it is in nodejs (https://github.com/nodejs/uvwasi), then pretty much we have a universal portable binary capable of doing relevant system operations. WASI is like a universal standard of system calls. Like a whole new POSIX standard.
Then one would just use WASM and WASI for all platforms.
Tasks
- ...
- ...
- ...