<div>Hi fellow C-lightning devs,<br></div><div><br></div><div>Channels maintain a set of secrets (revocation, htlc, commitment etc). Currently these are encoded as a PRNG seed, kept in a cleartext blob in the database.  In particular, we also share the secret seed to `channeld`.<br></div><div><br></div><div>It would be best if the secrets are not shared in cleartext to a daemon that communicate directly with the network: as defense-in-depth, we should ensure that `hsmd` holds the secrets.  Another design consideration is that the `hsmd` might someday be implemented as a hardware module, which might impose limits on the amount of data it can store (i.e. the PC might be able to handle thousands of channels, but the hardware module might not).<br></div><div><br></div><div>So I propose the below design instead:<br></div><div><br></div><div>1.  The channel seed is stored encrypted in the database.<br></div><div>2.  The decryption key is the HSM secret.  It could be a simple XOR with the channel seed, or we could load the HSM secret into a ChaCha20 PRNG and XOR the result with the channel seed.<br></div><div>3.  The `channeld` is given the encrypted form of the channel seed (and indeed all of the software other than `hsmd` cannot get anything other than the encrypted channel seed).<br></div><div><div>4.  The `channeld` is given a capability to request HSM to sign using a encrypted channel seed.  It passes in the encrypted channel seed and the message to sign.  This means the HSM does not have to store the channel-level secrets on a permanent basis (reducing the amount of memory the hardware module needs to implement).  The same capability also allows deriving and returning a revocation key.<br></div><div>5.  When a new channel is created,  we could just generate a random number and expect it to get decrypted to a corresponding decrypted random seed by the HSM.  This lets a hardware module not have to implement an entropy source (although a good hardware entropy source from resistor noise or similar could be used, and anyway how does the hardware module create the starting HSM secret anyway?).<br></div><div><br></div><div>The above design protects against:<br></div><div><br></div><div>* Remote memory read attacks.  The encrypted channel seed is not useable without the HSM secret key, even if it is somehow extracted from the `channeld` memory.  This is still less strong than if the channel secrets are stored in `hsmd` in their entirety, since if a separate remote memory read manages to extract the HSM secret, it is now possible to make use of the encrypted channel seeds, but we expect the HSM secret to be harder to extract than the channel secrets.<br></div><div>* Developer debugging of user databases.  The channel seed is encrypted and cannot be used by the developer to steal on-channel funds.  Giving user database will still leak privacy information, but will at least not make developers potential suspects if the user finds their channels stolen after providing the database to a developer to help debug.<br></div><div><br></div><div>However, it provides relatively minimal protection against:<br></div><div><br></div><div>* Remote code execution attacks.  This is because the `channeld` is given an HSM capability to use the encrypted channel secret to sign some messages, so it can be used to request a signature from the HSM.  One could argue that remote code execution is an immediate "I win" condition, though, since remote code execution could allow `cat hsm_secret`, although that would be reduced somewhat with a true hardware module (but with sufficient remote code execution it may be possible to directly access the hardware module and all its signing capabilities, so...).<br></div><div><br></div><div>Now the issue is transitioning from the current cleartext seed to an encrypted seed.<br></div><div><br></div><div>1.  Define a new database `intvar`, `"are_seeds_encrypted"`.<br></div><div>2.  We observe that if the database has no `intvar` of particular name, `db_get_intvar` returns the default value.<br></div><div>3.  At startup, if `db_get_intvar(db, "are_seeds_encrypted", 0)` returns 0, go through all channels and have the `hsmd` encrypt them.  We need to have this code enabled only with 0.6 and remove it on future releases (and tell users to pass through 0.6 if transitioning from pre-0.6).  Then `db_set_intvar(db, "are_seeds_encrypted", 1)`.<br></div><div><br></div></div><div>Regards,<br></div><div>ZmnSCPxj<br></div>