Musings on Key Management (aka 'Whisper Decoupling')


#1

Finally had a few hours this Sunday to think about the Key Management stuff.

Background

We strive to be a private means of communicating, whether that is via text, media or transactions. However currently, it is easy to see a user’s entire transaction history (public blockchain’s yo) based on whisper identity. To improve this there is a desire to generate new keypairs for both on-chain transactions and communication.

Previous discussions have been thoughtful & fruitful, but have had some issues addressing backwards compatibility. In this document, I want to propose a slight variation on the view on keypairs, offer some thoughts on UI and point out some high impact low hanging fruit user feature ideas, while keeping backwards compatibility in mind.

Note: With these changes we do not solve the privacy issue, as transactions will still be traced, however this approach immediately discovering transactions from a user’s whisper identity is substantially harder and creates a solid foundation to support solving the issue with transaction privacy such as AZTEC protocol in the future.

Bonus Wall of Shame Item! Transaction Privacy!

For previous conversations see @gravityblast’s:

Keypair Security Models

I would like to propose viewing keypairs not in distinction of their logical use but instead of their security model. This is to say keypairs in Status live under hot, warm and cold policies.

We should recognise that first, all Keypairs are in-fact logically equivalent. However all public keys can derive addresses but addresses cannot be reverted to public keys (that’s literally the security feature design), in other words:

All ‘Whisper Contact Codes’ are Wallets, but not all Wallets are Whisper Contact Codes.

This cannot be stressed enough and is a necessary concept to understand to retain backwards compatibility.

Hot Keypairs

These are in-memory generated keypairs, should be used for both Whisper & Wallets and do not explicitly require the user’s interaction for signing transactions or messages.

They are hardened child-derivations from the keypair currently used for Whisper in the application, derivations are deterministic based on;

  • chat-id
  • dapp/website hostname hash (open to alternative ways to do this)
  • integer? (i.e. point of sales tx id)

If a (on-chain) balance exists on these keypairs, the application should strive to automatically sign a (private) transaction to an address managed by a warm or cold policy when it is appropriate to do so (???).

Nonetheless manual transactions from hot keypairs (in the wallet) should be treated under a warm keypair policy, the user should still confirm signing of the transaction when sending a transaction.

Except under the case of designation of a ‘pin-less’ address, maintaining feature parity with Keycard.

Warm Keypairs

We can view these keypairs typically as traditional wallets. While whisper could be used here, it is not practical, as warm keypairs require explicit signing.

Note: Since all derviations come from master key, all usable wallets in Status are at least considered Warm keypairs.

Cold Keypair

This is a keypair that the Status application or Keycard has no control over. In Status it is a pointer to an address. It should ideally be a hardware wallet. The user can add as many cold wallet addresses as they like, for receiving only.

The hardware wallet may be another Keycard however this keypair should be refused to be loaded into the current application if designated under an account, and refuse to add the keypair as a cold wallet if it’s already loaded into the application, encouraging the user to maintain physical device separation.

Chat Considerations

hot root = current whisper key pair (afaik m/44'/60'/0'/0/2 ?) or whatever derivation structure specified on recovery screen (see Recovery section)

If a user wants a wholly new identity, they can logout and create a new account. Otherwise we can treat the hot root public key as their identity. This will allow us to maintain backwards compatibility, while providing unique identities per chat context moving forward.

All new clients should enter chats (1-1, private group, public) with a hardened (uses hot root private key) child-derivation off the hot root public key (iirc).

The user’s identity is unique to the chat context they are in. This allows the client to reveal the user’s true identity. Revealing is a signed message by the private key of the hot root authorising the unique identity, encrypted with the receiving clients public key, the receiving client decrypts & uses ecrecover to verify.

The ENS username will most likely host the hot root public key and this key is likely the signer of reveals, the client listens on this keypair for inbound contact requests and shouldn’t be used for transmitting messages in the future, but will be during N future releases period.

Moving forward it will be impossible to directly chat (or transact?) with anyone based on the hot root, however we will introduce a transitionary phase that lasts N future releases where existing contacts can still converse directly with hot root public key, but encouraged to upgrade. New clients can still listen to messages received on the hot root public key, but older clients would see responses in new chats from new public keys.

When joining 1-1 or private group chats, the client can automatically reveal themselves to their friends/added contacts. And can selectively reveal themselves to unknown contacts.

An advanced option toggle would allow the user to intermediate all automatic functions, requiring explicit consent before automatic reveals.

A reveal to a friend could also automatically be responded to in-kind with a reveal, and subject to intermediation by advanced option.

Joining Public Chats is more complicated. Since child derivations are hardened, it is not possible, or desireable to automatically derive possible keypairs based on chat-id’s. Nor is requesting every contact every time you join a new event.

To minimise bandwidth, we could construct a bloom filter that aggregates all chat-id’s and passes it to the most recently seen/‘online’ contacts, this should be done on chat join events. This would allow clients to query bloom filters locally and give plausible deniability opportunity to the end client (assuming they are intermediating their reveals). If the user is no longer in that chat, the response is dropped.

The user should also be able to explicitly reveal to another user who they are in a public chat.

This would mean that a user will have a ‘wallet’ or address for every Chat context. (See Wallet section)

DApp Considerations

Each DApp would also have their own key, a hardened child-derivation off the hot root based on hostname hash (or better? open to ideas).

With this approach we can offer a ‘proxy’ address to the DApp, in which we send a (private) transaction to, to be used to the DApp, and, since it is a hot keypair, we can also offer a streamlined user experience with the ability to ‘Not ask me to sign transactions’, this would require ‘preloading’ the DApp Address with X value, this allows the user a degree of control without excessive transaction signing.

This would mean that a user will have a ‘wallet’ or address for every DApp context. (See Wallet section)

User Interface Considerations

~~~~~~~~~~~~~~~~ [2:37] Intermission ~~~~~~~~~~~~~~~~

Tangential but important & easy wallet improvements

  • 24 word phrase recovery should be possible, please make it an option.
  • Emoji Guard,
    Seriously, it’s better than confusion between keyphrase and 3 words. and better than not having anything. Application proving itself to the user is important.
    Edit: This has been an issue for over a year now with no new improvements from anyone, if no one has better ideas and the current version is tied to a linguistic background that not all users are guaranteed to have then I vote we go ahead with this.
  • Omgplz let me add custom tokens already.
  • Social Recovery by splitting Key. (okay this isn’t as easy, but gogogo!)

Chat & DApps

In this setup, chat remains largely unchanged, most of the work is ‘under the hood’ and is backwards compatible.

However we will need to develop UI flows to do reveal.

Older clients that did not upgrade within the ‘N future releases’ period will see mysterious responses in new chats from unknown public keys. I don’t think this should be a concern.

The important difference here is that now Chat & DApp tab items can essentially hold their own balances. (See Wallet section)

Wallet

You should be able to send and receive from any key.

The wallet screen remains unchanged and is an aggregate of the user’s assets under all wallets.

The wallet should enumerate all addresses under hot, warm and cold that are used by the client, it should be a list ordered by their respective balances, displaying the top 3 token balances in each list item. To pull this off, wallet needs to be more responsive & intelligent in how it caches and queries balance data.

That means the list should be populated with 0 ETH balance DApp and Chat Addresses. It entirely possible to include this information in the current tab list and introduce a new Wallet tab list type. If these items are just generic new wallets, tapping them takes you to the existing wallet interface, but for that specific address, if it is a chat or dapp, it takes you do the chat/dapp, however we already have “View My Wallet” in 3 dots, conceptually this could be “View DApp Wallet, or View Chat Wallet”

Creating a new wallet is just an integer child-derivation from warm root. Creating a new wallet is client-side only. On recovery these will be forgotten (unless they have balance) until we can encrypt the application database and upload to decentralised file storage.

Creating a cold wallet is read-only, receive only and requires the user to enter in an address. That is not under control of the application.

This also allows us to create smart contract based wallets, ie multisig, but I think this should be the next iteration.

A wallet address can be revealed in a chat context that is seperate from the unique identity and the real identity via the send/request commands.

This approach allows us to re-use many existing flows and UI elements without introducing major breaking changes or too many new UI elements. I imagine most of the work would be efficiently managing the balance data.

Recovery

Since we made efforts to use similar key phrase recovery as other applications, Status should be compatible with any other HD key structures, such we should auto-detect what structure the recovered keypair uses based on other popular applications compatible with BIP44, and/or offer the user to select or define their own structure.

It might even make sense to support multiple HD key structures, as users might use the same keypair on different applications.

While I’m at it, by now we should also offer to import other private keys into Status

Conclusion

The above suggestions seem to achieve our goals while keeping minimal UI changes and retaining backwards compatibility, I have used some terms interchangeably and probably have some terms wrong (it’s been awhile)

(Also why does the Wallet say ‘Deposit’ instead of Receive? Not very accurate imo)

I’m sure I’ve missed some considerations and would love feedback!


Profile information Structure - Please review
#2

Hey @jarradhope thanks for this topic! There are a lot of things I would love to discuss about but I’ll try to write a quick reply before we have the dev meeting. Then I’ll add more questions/ideas.

hot root = current whisper key pair (afaik m/44’/60’/0’/0/2 ?) or whatever derivation structure specified on recovery screen (see Recovery section)

The current whisper key pair that we use is the same of the first BIP44 wallet we use, so for now it’s m/44'/60'/0'/0/0

The initial idea was to use EIP1581 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md for chat keys, and in general for hot keys that can be exported from the keycard.

If we have in mind to have warm and hot keys, do we still need to decouple whisper (hot), and wallet (warm) so that they are manage in different ways?

If a (on-chain) balance exists on these keypairs, the application should strive to automatically sign a (private) transaction to an address managed by a warm or cold policy when it is appropriate to do so (???).

Just to see if I understood: if a hot wallet has a balance, the app helps the user to move the balance to a warm or cold address. correct?

Warm Keypairs
We can view these keypairs typically as traditional wallets. While whisper could be used here, it is not practical, as warm keypairs require explicit signing.
Note: Since all derviations come from master key, all usable wallets in Status are at least considered Warm keypairs.

If I understand correctly, a BIP44 wallet is a warm wallet. So it’s basically what we have now as the only visible wallet, but we should not use the same key for whisper like we are doing now.

Cold Keypair

so here we can have view only addresses right? in case of keycard, any BIP44 will be a view only address, so only the address is kept in memory, never the actual key.

Each DApp would also have their own key, a hardened child-derivation off the hot root based on hostname hash (or better? open to ideas).

This is a good idea, although we can do it only with dapps with a domain. (.eth or any other domain).

What can we do if it’s just on ipfs/swarm? maybe we can use the ipfs hash, but then an update of the dapp will change it.
Related discussion: https://ethereum-magicians.org/t/meta-we-should-value-privacy-more/2475


#3

Very much this! I’ve mentioned earlier in previous posts that a coupling of chat and wallet keys means you’re treating the security of one the same as the other. I’d like to verify that you are detailing this out in your post, but also reminding us that “whisper keys are still wallets, so they also need to provide that functionality just in case it is needed” (to rephrase the post).

I’d also like to see how we can update the schematics of key derivation and management I’ve created and linked in the first historical post you linked. I believe those help us reason and intuit the uses of keys for Status, as well as outside contributors when evaluating us.


#4

My understanding is that using the current whisper key (m/44’/60’/0’/0/0) as the hot root is necessary to allow backwards compatibility in this proposal. Is that right?

If yes, one thing that bugs me is that when Keycard is used, the hotroot keypair should be exported from Keycard, and we had planned to allow export only on a set of paths (m / 43’ / 60’ / 1581’/x/x) defined in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md

Another way to put the problem: if we decide that the hotroot is down that path (m / 43’ / 60’ / 1581’/x/x), how much harder backwards compatibility gets?


#5

hot root should be fine to be exported to a trusted device as it’s living in memory anyway.

if you change the derivation path, and do not expose it to the client, then it is unable to decrypt messages send to that pubkey and it wouldn’t be unable to sign transactions, important if you want to change ens username ownership.

I’m not opposed to the derivation path change, but OP was kind of making a minor case against the idea of seperating keys out by their logical use in the derivation path, since there’s nothing technically stopping keys from being used for either approach, and if the team responsible for the changes is not fully aware of the consequences I’d recommend against doing it, at least for this iteration.

You would have to:

  1. Export the original hotkey
  2. Remove all responsibility from the key, ensure the user/client has moved all assets, notified all contacts (and dapps) of the change to the new key
  3. Log user out, have them sign in again under new derivation path.

2 is fairly problematic, if you give them no ability to define their own hd key structure then you are potentially locking a user out of their assets, which is why I was suggesting we include this in the recovery screen for advanced users.

That would mean that for new accounts we can use a new derivation path, but we still autodetect and use our current derivation path, as well as ledger/metamask/etc key structures


#6

Thanks !

I have a hard time figuring out what should be the exact path of the hotroot that would best take into account the following constraints. Please challenge them, they need to actually :slight_smile:

  • Current implementation of Keycard imposes hotroot to be on m/43’/ 60’/1581’/x/x paths
    Current Keycard code only allows to export the key pairs of the following paths m/43’/ 60’/1581’/x/x. This is how it is implemented, and we issued EIP-1581 to try to normalize this.

  • Hotroot can not be m/44’/60’/0’/0/0 for Keycard security
    Keycard should not be able export m/44’/60’/0’/0/0, since it sounds quite contrary to its fundamental to be able to export such a common BIP44 wallet path (and our current wallet path)

  • Hotroot should be m/44’/60’/0’/0/0 from a migration standpoint
    Since our current whisper key is m/44’/60’/0’/0/0, if hotroot is different than m/44’/60’/0’/0/0 then we have to go through your steps 1-2-3 below which looks like a no go in terms of user experience

And to focus on the keycard, what we have to decide now is if we think and implement a new security scheme to allow/forbid export of key pairs than the one currently implemented!


#7

Ah I see, last I recalled the keycard let you define the path for deriving whisper keys (hot root) which could be set once every initialization, I don’t recall this being hardcoded.

If there’s strong objection to allowing that ability and a preference to hardcoding it, then I think that’s quite opinionated, in most cases I’m in favour of generalisation and flexibility. The hardcoded approach definitely makes the keycard not backwards compatible.

However we could make it work, a hack solution for old accounts is we would leave the key entirely in software as it currently stands, but still following keycard userflows for everything else. The user experience would be pretty similar, however security profile is not enhanced by keycard for keys derived from m/44’/60’/0’/0/0, but would remain as is now.

New accounts could use the new structure, and we can support both in recovery.


#8

The path is not hardcoded, but only keys under the EIP-1581 root can be exported. This means BIP44 keys cannot be exported. There are a couple of reason for doing it this way. The first is that since the Keycard has no UI, it cannot warn the user about the path of the key being exported, so we must limit what is exportable to provide reasonable security guarantees. Another reason, is that AFAIK no hardware wallet allows exporting keys at all at the moment and I feel that without the path limitation this feature wouldn’t be really welcome by existing hardwallet users. I am thinking about the Keycard-Ledger integration, where by adding the EXPORT KEY command we make the Ledger usable with Status.


#9

Okay that makes sense, sgtm.


#10

Ok, this means we don’t change current policy of Keycard regarding exporting keypairs. We will comply with EIP1581

This also means that when we implement the hotroot scheme described above

  • we will use hotroot = m/43’/ 60’/1581’/0/0 by default when creating a new account (if not these accounts cannot be Keycard accounts or cannot be exported easily to a Keycard)
  • when recovering an account with BIP39 the user will be able to chose another hotroot if he wants too (he wants it to match with his ENS).

For the very short term which is for Keycard beta, we discussed it again with the team and we plan to use m/43’/60’/1581’/0/0 for the whisper key both when creating a new keycard account but also when importing an account on Keycard through BIP44 (@dmitryn is implementing this in the next days).


#11

One extra remark: as a user I’d like to be able (as an option for instance when opening for the first time a new dApp) to use a warm keypair when using a dApp, I am thinking especially dex dApps.


#12

I created a proposal with the actual implementation following this and the pasts posts:

https://notes.status.im/QxNC1H2cQMG7t8GvEb_Ctw

The note describes the first step of the keys update. The second step would be the actual use of different keys for chats and dapps but that requires more work in different teams and parts of the application.

I would like some feedback on that, feel free to add comments there or here please.

/cc @jarradhope @guylouis @michele @petty @hester


#13

Multiple wallet keys : for now we save only the BIP44-0 key , so there’s no way to derive other BIP44 keys in normal accounts. What are the security implication if we want to use the BIP44 keys parent, so that we can use it to derive any BIP44 child key?

Can you be a bit more specific here? Are you asking what implications are associated if we want to use BIP44-0’s parent?

If we use BIP44-0 to derive more wallet accounts than if it is compromised, everything else down the hierarchy is also compromised.

We could only use BIP44-0 as a generation key, but that would lose some compatibility with other wallets, as well as require some migration of accounts in current Status users.


#14

5 - Recovering an old account in the New Status : if needed we can have an advance option so that we can recover an old account in the New Status. This account will have the same keys of the Old Status.

An additional option would be to do something like MetaMask does with the allowance of importing a private key that’s “separate” from the original derivation path. We can derive things the old way and just save the priv/pub separately somewhere.

I think we should be doing this anyway if we want people multiple options for using Status with their accounts created from other devices.


#15

I think the point is to chose for a Status account (non Keycard one) which key pair we store in the database.

Today we store BIP44-0, but that’s not enough since we want to enable our wallet to access other common wallets paths, or even custom one. From a security stand point how far up the path can we go ? I remember you said you’d rather not have m stored in the database. Can we store m/44’ from a security stand point ?

Note there are also discussions about which derivation paths will be used for dApps keys here : https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742/4

example of other wallet paths
MyEtherWallet_com


#16

There isn’t much difference in security between m and 44. My initial goal in preferring not to store it was to minimize the damage of a single leaked key. For instance, if we never stored it, and somehow someone got a hold of the whisper key, they wouldn’t be able to do anything to the wallet.

In the context of storing this key, since it is never actually used by the user, the only way it can be recovered is through hacking the app (still a possibility).

I lean on the side of functionality and options to the end user, we just need to be damn sure we store and secure this key well, as its recovery gives access to everything. I just don’t see an option otherwise really to add the ability for all this additional functionality to the user.

The separation of use of these keys still allows us to optimize security appropriately for each key’s use case.


#17

thanks @petty! Yeah this part is maybe out of scope, but I was just thinking if we want to have multiple warm/cold wallets (it’s not really in the main discussion, but I was thinking about it since we are already changing the keys).
With the hot root key we will be able to derive hot keys for many purposes and it’s fine, but they won’t be BIP44 compatible.
If we want to also have many BIP44 wallets like metamask does, we need to have the BIP44 parent key saved somewhere, unless we ask the mnemonic every time a user wants to add a wallet in the account, which maybe can be a solution.


#18

@petty Yes good point! That could be an option, so we could import any key as a wallet.

Talking only about different paths, I wrote something in the different derivation path options paragraph:

Different derivation path : we will have an “advance setting” where the user at account creation/recovery will be able to decide the derivation path for wallet keys. The default continues to be the BIP44 keys path.


#19

@petty we could also skip this part and think about the implementation in a second phase, when the rest of the key management if finished.


#20

Yeah, I feel like once the main change is over, minor changes that we’re discussing could be handled relatively quickly without too many migration issues.