WebOfTrust / keripy

Key Event Receipt Infrastructure - the spec and implementation of the KERI protocol
https://keripy.readthedocs.io/en/latest/
Apache License 2.0
56 stars 53 forks source link

Change storage and indexing for Next public Keys #321

Open SmithSamuelM opened 1 year ago

SmithSamuelM commented 1 year ago

All private keys are encrypted in the keystore. The next public keys may benefit from also being encrypted.

Currently they are not exposed in the KEL because only their hashes are exposed. But it would be better to also protect the the not yet exposed next public keys in the database.

The next public keys do not need to be stored at all but recreated from the private keys. The next key hashes could be used as the database indexes to retrieve the private keys. Then only the private keys need to be stored encrypted and the next public keys only appear as hashes.

Because the keystore does not know which public keys have been exposed in a KEL, a generic solution is to index the encrypted private keys by the hashes of their public keys.

That way the public keys are not persisted in the database so a post quantum attacker could not get to the private key through the public key they would have to invert the hash or break the encryption. Current ECC symmetric encryption algorithms (ChaCha Salsa) are post quantum safe. [quantum safe encryption[(https://crypto.stackexchange.com/questions/70492/how-resistant-are-stream-ciphers-like-salsa20-or-chacha-in-a-post-quantum-world). But have the problem of key sharing. This is not necessarily a problem for a keystore which is only encrypted to its owner and is never shared. Post quantum safe PKI is required for post quantum safe asymmetric encryption to protect against a post quantum attack inverting the public encryption key to get to the private decryption key.

To get the public key from a given public key hash, the private key is looked up and then the public key is rederived. This is only needed when rotating a key set which returns the prior next now newly current signing public keys.

A query to the database to sign using the public key would first hash the public key from the query then look up and decrypt the private key. A read through in memory cache that maps public keys to their hashes could be used to minimize the hashing on signing at scale without ever persisting the public keys.

The database design is changed to use the hashes of the public keys as indices into the database and not the public keys themselves

To support cryptographic agility the hash uses can be changed similarly to how the encryption key is changed. When changed then the private key records are moved to new ones with the new hash. so only one hash algorithm is used throughout the database to hash public keys

pfeairheller commented 1 year ago

Needed for Signify

SmithSamuelM commented 1 year ago

To clarify, the proposed change only uses hashes of public key as indexes for encrypted private keys even for current public signing keys . This is because an inadvertent rotate on the keystore that does not result in a rotate on the KEL could expose a public key in the keystore making it vulnerable to post quantum. The keystore uses the same hash everywhere for public keys but can upgrade the hash for crypto agility on a key store wide basis. (edited)

AFAIK there is never a need to access next public keys outside the keystore until after then have been rotated to current signing keys to be used for a KEL rotate. So the transmission of the unhashed public keys to the caller of the rotate can be protected. Some details on the calling API to be worked out.

SmithSamuelM commented 1 year ago

I think what this means is that the pubs list in keeping.Publot is filled with the digests of the public keys not the public keys. and then to return public keys in an external method like .incept or .rotate means to regenerate them from the private keys before returning them and optionally to encrypt the

SmithSamuelM commented 1 year ago

The API to sign doesn’t change, its just that under the hood to look up the private keys, the sign function would hash them because the private keys are stored by the hash. This means that someone calling sign function would not see a difference.

The reason no public keys should be stored in the database is that there is no whay for the keystore to know which public keys have been published in a KEL and which ones have not. So to be truly post-quantum protected the key store MUST not store public keys in the clear even as database indices. Now that I have revisted my original thinking I remember the thought process I went down when I originally created the issue. At first I thought that only need to use hashes for the next keys but that is no guarantee because the keystore could get rotated but not published in a KEL for some time (due to group formation or other long time decisions) which creates a longer time period (much longer than network latency) for a quantum attack on the database.

So best post quantum protection is to never expose public keys via the keystore by only using digests of public keys and only store private keys encrypted.