Closed augustin-cheron closed 3 weeks ago
Oooh. Interesting point! At minimum, we must point this out in the README (#1911).
I love your proxy key solution, but implementing it would pierced the veil of secrecy between the API and the actual bytes of the private key. Anyone who got a reference to the polyfilled key could just exportKey()
the private key bytes, which is not true today, and not true of real CryptoKeys
.
Until there's support for Ed25519 keys everywhere, I think wherever there's an application where you need to store the keys locally you'll just have to do it in the conventional way (eg. generating your own and storing it, using importPrivateKeyFromBytes()
when you need to use it with web3.js (#1813).
Thank you for having taken the time to review this. I loved the fact that you used the Web Crypto API in this new version of web3.js. I can use my own polyfill and it just works out of the box with the rest of the library.
How about implementing a unique flag at the start of the proxy key, which would prevent key extraction in the polyfilled exportKey
function whenever this flag is detected?
With a big enough KEY_HEADER (32 bytes?), real-world key collisions should not be an issue.
The only issue I can foresee is if a user can bypass the polyfill and call the original exportKey
function (which will happen when they remove the polyfill from their dependencies).
let rand = crypto.getRandomValues(new Uint8Array(32));
let header = KEY_HEADER;
let key = new Uint8Array(header.length + rand.length);
key.set(header);
key.set(rand,header.length);
let proxyKey = await crypto.subtle.importKey('raw', key, 'AES-GCM', true, ['wrapKey']);
crypto.subtle.exportKey = async (format, key) => {
let pk = await originalExportKey('raw', key);
if(pk.slice(0, KEY_HEADER.length) == KEY_HEADER) {
throw new Error('can not export key');
}
// ...
}
The only issue I can foresee is if a user can bypass the polyfill and call the original exportKey function…
Yeah, exactly. And so can an attacker, by grabbing a fresh copy of SubtleCrypto
from a new iframe
they create.
const frame = document.createElement('iframe');
document.body.appendChild(frame);
const stolenKey = await frame.contentWindow.crypto.subtle.exportKey('raw', proxyKey);
We've pointed out this limitation in the README (#1911).
Because there has been no activity on this issue for 7 days since it was closed, it has been automatically locked. Please open a new issue if it requires a follow up.
The current implementation of the ed25519 polyfill does not support storing keys in IndexedDB without exporting them. As per the W3C Web Crypto API, a
CryptoKey
should implement the structured clone algorithm, enabling direct copying without exposing the private key to JavaScript.To address this, I propose to add a CryptoKey directly into the generated keypair instead of using a memory store.
With this approach, we can identify a polyfill key by checking if
_proxyKey
exists. Here's an example of how thesign
function could be implemented:This change allow to create or load wallet from index db like this