New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Solve Key Management #73
Comments
In response to https://ethereum-magicians.org/t/non-wallet-usage-of-keys-derived-from-bip-32-trees/1817/6 : (copied here because I am not allowed as a new user to put more than 2 links in a response). The current proposed API in EIP1775:
Implies that access to a dApp specific private key is given to the dApp. I believe this is not ideal as it means the dApp now needs to properly handle the private key. I agree with you (@3esmit) that it'd be ideal if the dApp could instead request signing/decrypting messages to the wallet, using the dedicated dApp key. Potentially using a permission based design such as EIP-2255. However, the challenge is that the decryption/signature method provided by a wallet may not fit the dApp needs. However, in terms of decryption, we can see that various schemes are used in the ecosystem and it may be difficult to pick one:
Another solution would be to provide a generic API that supports several encryption. An idea would be to use CryptoSubtle as the API reference and assume that in the Browser world, some of the encryption supported by Crypto Subtle should be supported by the Wallet API. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I got pinged from your recent comment on EIP-2844. I'm glad to see your looking at using EIP-2844. Reading above, I think there's a few ways we could get to your end goal of being able to allow encrypted/signed messages to be usable without needing authorization requests each time but I'd like to drill into your requirements a bit more before I make a recommendation about using EIP-2844 (or we come up with a way to re-adjust it). Is the end goal here to be able to send and receive messages without performing authorization requests each time? From what I'm seeing this is the ideal requirements you need for some other work:
It seems like there's a few intended goals here which could be broken down in a variety of different ways to achieve the intended outcome. However, some of my assumptions are coming from a DID based background that I'm not sure if they hold for your use case if I twist and rejig things a bit to align for you. The main reason I'm asking is to try and keep the APIs in EIP-2844 as generalized as possible so that it can be applied across a variety of use cases while still making sure it addresses your needs.
Are you utilizing the key pair as an identifier of sorts here? The heart of my question here is to try to figure out what's driving the need to be able to recover the keypair later. I'm thinking it may be possible to utilize the DID as the identifier so that the key management solution can be decoupled from the identifier persistence. 2 and 3 I presume are about trying to reduce consent request fatigue. Is this correct?
This goes back to trying to figure out the purpose of the keypair and see if it's being used only for cryptographic operations or if it's behaving as an identifier of sorts as well. I presume based on this assumption that there's a need for greater privacy guarantees. Am I off basis here?
Is there a need to ever re-correlate these keypairs down the road (e.g. two messaging groups are merged later on) or are they being treated more like pairwise interactions that MUST NOT interact at any point in their lifecycle? |
References: |
Yes, correct, the goal is to be able to:
I believe that the user should still grant authorization at some point. I do not know what the best UX would be but once per session would make sense at first (ie, when the dApp connects to the wallet).
Yes, thank you for helping me clarifying the use case.
Yes, the keypair is used as an identifier for chat purposes. It is the chat identity of the user.
Yes, correct, maybe "programmatic" is not the best qualifier for it. We cannot expect the user to approve the decryption of every incoming message and the signature of every out going message. Signature and decryption MUST be somehow tied to the chat identity above. Noting that regarding encryption, we use double ratchet protocol. I realize that I haven't looked into/expressed the actually need for that. The dApp may after all need access to a decryption private key. I need to review this point.
You are absolutely right, the user MAY NOT want to reveal their Ethereum account when revealing their "chat" identity.
I don't believe there would be a need to ever re-correlate these key pairs. The use case I have in mind is that a user may hold tokens ABC and XYZ in their Ethereum account. They want to participate to discussion in both ABC and XYZ communities however, do not wish to link their identity across the forums. if we restrict the design to "1 Ethereum account = 1 chat identity" then it means the user has to move their asset to enable the unlinkability between the chat identity which is not ideal. |
|
Yeah, my thinking was similar to what's done with the authz of viewing an account address per domain name.
Sounds good, I've heard of status' app, but have not played around with it yet. I'll give it a go to get a better understanding of your needs.
Interesting, so with EIP-2844 the idea is that the identifier is abstracted to the DID layer and the public keys become what are known as "verification methods" in the did documents which to date have always been public keys. I'm thinking there's some value in decoupling this identifier layer from the cryptographic material so that a common identifier can be used without needing to do key recovery on different devices to maintain chats. Rather you can just add a new key to the DID Document. This is one of the key value props of DIDs. Is that something that would make sense for your team to do (I'm thinking it may lead to changes in how you handle key management in the app as well) at this point or does fall outside the scope of the goals of this work?
That makes sense - what's interesting here is it seems like the browser is only being used for ingress communications. Do you plan to perform things like encryption and signing from the browser as well or is it mainly being used for reading messages?
This will make things a bit more complex, but not outside the realm of possibility. We've looked at how the X3DH algorithm could be built into the JOSE stack and believe it's possible, but no one has gone and defined a method to achieve it yet. This definitely introduces a few additional complexities into play now because from the sounds of it the waku keypair is actually the long term identity keypair in the X3DH algorithm. The implications here are that by utilizing the same waku keypair on multiple devices a compromise of a single device I believe compromises the entire communication channel. Things like Sesame protocol and Message layer security have been the latest improvements in the space to make it possible for multi-device communication and group communication in order to handle these new complexities. I'm curious is limiting the affects of a single device compromise a concern here or would the user be expected to set up a new communication channel if one device was compromised?
Ok, thanks that makes sense now and should make it easier to keep things decoupled better.
Good to know, and I agree with the design choice. One thing worth considering is that when decoupling the identifier layer from the crypto material with DIDs, it does become possible to do this recorrelation with a bit of advanced usage of DID Documents. I'd leave this out of scope though for now, since it's really a separate feature of sorts in my mind. Thanks for answering these things. What I'm gathering here is that there's two recommendations I'd make
|
There are mainly two scenarios to be considered:
There are hopefully synergy between both scenarios, however the outcome may differ because in the case of (2), the user has access to the Status app that facilitates the backup and management of the chat key, used for signature and encryption purposes. The Status app can act as a secure vault for the main "account" of the user. In the case of (1) the may not be such secure/main account as a given dApp may be exclusively access via the browser with a generic Ethereum Wallet being the secure enclave for keys. (2) as discussed with @cammellos: The discussion was mainly focused around compatibility between Status app and the Chat SDK. Here are some conclusions we can extract:
to be continued. |
After further review, it seems that currently, the most used method is C: generate a private key from an Ethereum account by signing data and using the (hash of) the resulting signature as private key. A potential vector of attack is a website impersonation where a user is directed to scammywebsite.com and asked to sign with their wallet to generate a private chat key. In github.com/status-im/dappconnect-chat-sdk we are mitigating the drawback by using EIP-712 and including the apps' domain name as part of the data to sign (onlySignOn field, wip), to prevent the same key to be generated on two different websites. We also intend to ask the user to check said field. Yet, this still involves the user's attention to verify that the domain in the signature matches the domain website. Ideally, this domain check should be done programmatically. Option D: Use EIP-1775 would help on this matter. Another proposal is to let the user specify a password-like custom text to be added to the data to be signed.
|
First of all, I believe this a decent work. It seems you thought of all the details. As far as I understand, the security matter here is scamming, phishing via the website or spear phishing. Also, there are some attacks like DNS poisoning that usually requires being MiTM. (If you need more information, please check here: https://www.kaspersky.com/resource-center/definitions/dns) Your security measures are enough for current security best practices. But you can think like we are selling a knife or a weapon for a specific purpose. We can tell our customers not to kill themselves with a knife or weapon, but we can't stop them from doing it. I don't think there will be a magical solution to stop scamming, impersonation or phishing soon but what we can do here is to teach our users not to click or be bait on them. There are some considerations for preventing fake websites, but they require a centralized solution that must be permission-based or controlled based. Therefore, it is not suitable for Status' soul. Even you create centralized automation that can verify Dapps before signing with your wallet. Still, lots of people can be deceived. The solution is always to design the process as simple as possible not to confuse users' minds. The UX itself should show users what is not secure, which you are already planning to do it. PS: "Ideally, this domain check should be done programmatically. Option D: Use EIP-1775 would help on this matter." This is a perfect solution. The best way to see the attacks is to do a threat modeling and create an attack tree and a threat/attack traceability matrix to ensure the attack surface. If you want, we can work on it together (You, me, plus Fred) @OxFred @D4nte |
I agree largely with the sentiment that @serhanwbahar has expressed. Solving for the phishing problem is going to be hard and isn't current security best practices of today. Obviously if we can it would be best to solve this, but I don't believe that the solution proposed by @D4nte with phishing problems left out of scope couldn't be extended later when a more decentralized solution is available to solve the phishing problem. Today, the most common way I've seen to solve this is a DMARC record which relies on DNS in order to establish trust hierarchies. As @serhanwbahar pointed out this will centralize the solution in a way that goes against the ethos of your team (and the ethos of the ecosystem). I've looked at ways in which things like a DAO or TCR could be used to decentralize the trust hierarchies, but solving this seems to be a yak shaving exercise which isn't fundamentally assisting with the overall focus of the problem originally described. For that reason, I think it makes sense to leave the phishing issue out of scope as well. Additionally, while I do have a preference towards the utilization of DIDs and seeing that ecosystem expand further into the ethereum ecosystem; I also understand the desire to remain aligned with the account based approach. It's likely to be the solution which will align most closely to other people working in the ethereum ecosystem and so is likely "good enough" to go forward with. |
Moving this to icebox as we have a current solution. We can review in a year's time to see if the ecosystem has evolved or changed security practices. Especially regarding EIP-1775. Regarding the threat/attack traceability matrix. We can do that once any of the SDK/project that uses the method proposed above is confirmed market fit and we decide to document this practice as best practice in the usage of js-waku. |
Out of scope for Waku at this point in time. Would be good to see what https://github.com/status-im/status-web does |
Problem
For identity (signatures) and encryption purposes, the user needs access to a key pair, therefor referenced to as Waku keypair.
There is currently no straightforward solution possible via the standard Web3 Wallet API.
Cryptographic needs
The following encryption and signature schemes are defined in Waku v2 and would ideally be available with the adopted solution. However, it can be changed/evolved if we go for a generic API-type solution:
Waku, see 26/WAKU-PAYLOAD for details:
The encrypted data is
flags|payload-length|payload|padding|signature
withflags = size of payload-length | signature-presence
(2 bytes field).Encryption and signature can also be defined at application level. For example, EIP-712 is used for a couple of smart-contract and non-smart-contract enabled apps.
Ideal solution
For an ideal UX, the following properties need to be satisfied:
tl;dr
Jump to Moving Forward to see the proposal and work back to selected solution(s).
Potential Solutions
A. MetaMask's
eth_decrypt
APIOverview
As demonstrated in https://github.com/status-im/js-waku/tree/main/examples/eth-pm-wallet-encryption, MetaMask provides an API to:
eth_getEncryptionPublicKey
eth_decrypt
Also see https://ethereum-magicians.org/t/eip-1024-cross-client-encrypt-decrypt/505
Properties
Preliminary conclusion
This solution does not satisfy enough properties to be considered.
We could review the API and propose improvements but it may be better to design a new API from scratch that fits our purposes instead.
B. Generate keys and provide ways to back up and recover
Overview
A naive approach is to simply generate a keypair using common JavaScript libraries.
A way to backup and recover the keys needs to be provided to the user, independently to their Ethereum account.
Properties
Preliminary conclusion
Property 1 is a challenge, the only challenge, of this solution.
It is a strong candidate, only upped by a solution that would allow deterministic derivation of keys from an Ethereum account.
C. Generate private key from Ethereum signature
Overview
Ask the user to sign a message such as
"This signature is used to generate your waku private key, do not share with other parties"
and hash the resulting signature. The hash is then used the Waku private key.Properties
eth_signTypedData
a. It is unsure whether we are introducing a data bias by using the hash of a signature as a private key. I assume it somehow reduces the set of possible values. More research would be needed to affirm it does not makes the private key less secure due to the pseudo-randomness property of the source (ECDSA signature).
b. dApp and wallets usually do not put an emphasis in keeping signatures secret (in comparison to keeping private key secrets). Hence, the resulting signature could be leaked by the wallet or dApp framework simply because this specific, odd, usecase was not kept in mind when designing the wallet/dapp
c. User footgun: Most of the security of this method rely on the user refusing the sign the exact same message for another dApp.
Preliminary conclusion
While this method would allow to fulfill most properties with the current Web3 API, it brings some UX security challenge.
At this point, it would be safer to push the user to backup their Waku key the same way than they backup their Ethereum key than asking them to never sign twice the same message with two different dApp.
Do note this is used by other projects, hence this conclusion may need revision:
D. Use EIP-1775
Overview
tl;dr:
EIP-1775 propose the implementation of new wallet api
wallet_getAppKeyForAccount
that produce an application private key, unique to the dApp and derived from the user's Ethereum account.The dApp is identified by there domain name, making sure that no 2 dApp can access the same private key.
Properties
Ethereum private key | dApp domain name
Preliminary conclusion
Each key is tied to an app's id (e.g. domain name).
For a use case that involves several platforms (web, mobile) then the generated waku key could be different.
Which makes it more complicated, yet possible, for a user to preserve the same identity across platforms.
Cross-signing methods could one way to resolve this (see Matrix protocol, more investigation necessary).
This approach also mean that the dApp is trusted with the waku private key.
Overall, this could be a possible long term approach. More discussion is needed to understand why this EIP is not adopted.
A safer solution would be to have the wallet expose decryption and signing APIs for non-wallet purposes that do not require user approval at each action, but only once per key/dapp/session: e.g., user confirms that the dApp can use non-wallet key to decrypt and/or sign for the whole session.
EIP-2255 proposes such permission based design.
However, this brings other challenges such as: what decryption/signature method should be allowed?
E. Extensible crypto for wallet
Overview
An API that allow registering and then using algorithm with the wallet by way of wasm blob.
Principally designed for ZK algo.
See https://ethereum-magicians.org/t/extensible-crypto-for-wallets/2546/19
Properties
TODO
Preliminary Conclusion
It is not really adopted (no EIP). It has potential to provide a generic solution that could be used for our use case but it may also be overkill as we only need signature and encryption using existing algorithms, not new ZK ones.
F. EIP-2844: Add DID related methods to the JSON-RPC
Overview
This EIP describes three new methods to add to the JSON-RPC that enables wallets to support Decentralized Identifiers (DIDs) as well as JSON Object Signing and Encryption (JOSE). These standards enables wallets to support data decryption as well as authenticated data, both in standard formats using JOSE. With these new methods apps can request the DID from a users wallet, from which a DID document can be resolved. The DID document contains public keys that can be used for encryption and signature verification. This enables Alice to discover Bobs public keys by only knowing Bobs DID. This EIP does not enforce the user of any particular DID method or JOSE algorithms, wallets are free to implement these however they wish.
Properties
did_authenticate
API that takesaud
(domain name of the dApp) andpaths
(permissions) as input. EIP-1581 could then be used for deterministic generation of the DIDs/keys from the Ethereum account.did_authenticate
first to give specific permission for this dApp (e.g. sign), no user interaction would then be needed when usingdid_decryptJWE
as long asaud
andpaths
matches a previous auth.did_authentication
. Thepaths
format is not defined, maybe it could be terminated by an index that the dApp could increase to recycle key? The UX implication would need to be reviewed.Preliminary Conclusion
While this API does not perfectly fit our use case (see 3.), it is very close.
It proposes standard formats to generate identities, sign and decrypt payload in a generic manner.
It does not dictates key management for the DIDs which may still need standardization.
Moving Forward
(B) seems to be the best way forward in short-mid term for several reasons:
Long term, we need to investigate
D/EIP-1775F/EIP-2844, better understand the reasons why it is not adopted and help its adoption/design.Preference of F/EIP-2844 over D/EIP-1775 is simply because the former let the wallet handle the private keys, instead of the dApp.
Other solutions to consider
References
The text was updated successfully, but these errors were encountered: