# Symmetric SSSS

[MSC1946 (Secure Secret Storage and
Sharing)](https://github.com/matrix-org/matrix-doc/pull/1946) proposed a way of
storing encrypted secrets on the server.  In the proposal, secrets were
encrypted using a Curve25519 key, which was chosen to allow easier migration
from key backups that we created before the backup key was stored using it.

However this does not provide any guarantees that data stored using the
proposal came from a trusted source.  To remedy this, we propose to change the
encryption to use AES with a MAC to ensure that only someone who knows the key
is able to store data.

## Proposal

* The `m.secret_storage.v1.curve25519-aes-sha2` method proposed in MSC1946 is
  removed.

* A new method, `m.secret_storage.v1.aes-hmac-sha2`, is added.  With this
  method, the Secret Storage key may be any size (though 256 bits is
  recommended), and data is encrypted as follows:

  1. Given the secret storage key, generate 64 bytes by performing an HKDF with
     SHA-256 as the hash, a salt of 32 bytes of 0, and with the secret name as
     the info.  The first 32 bytes are used as the AES key, and the next 32 bytes
     are used as the MAC key
  2. Generate 16 random bytes, set bit 63 to 0 (in order to work around
     differences in AES-CTR implementations), and use this as the AES
     initialization vector.  This becomes the `iv` property, encoded using base64.
  3. Encrypt the data using AES-CTR-256 using the AES key generated above.  This
     encrypted data, encoded using base64, becomes the `ciphertext` property.
  4. Pass the raw encrypted data (prior to base64 encoding) through HMAC-SHA-256
     using the MAC key generated above.  The resulting MAC is base64-encoded and
     becomes the `mac` property.

  (We use AES-CTR to match file encryption and key exports.)

  If the key Secret Storage key is generated from a passphrase, information
  about how to generate the key is stored in the `passphrase` property of the
  key's account-data in a similar manner to what was done with the original
  `m.secret_storage.v1.curve25519-aes-sha2` method, except that there is an
  optional `bits` parameter that defaults to 256, and indicates the number of
  bits that should be generated from PBKDF2 (in other words, the size of the
  key).

* For the purposes of allowing clients to check whether a user has correctly
  entered the key, clients should:

  1. encrypt and MAC a message consisting of 32 bytes of 0 as described above,
     using the empty string as the info parameter to the HKDF in step 1.
  2. store the `iv` and `mac` in the `m.secret_storage.key.[key ID]`
     account-data.

* The `passthrough` property specified in the "Enconding the recovery key for
  server-side storage via MSC1946" section of MSC1219 is removed.  The primary
  purpose of that property was to allow easy migration of pre-MSC1946 backups,
  so that users could reuse the backup recovery key as the Secret Storage key
  without needing to re-enter the recovery key.  However, since we are now
  using a symmetric encryption algorithm, the client needs to know the key that
  is used to encrypt, so the purpose of the field cannot be fulfilled.

* Signing the Secret Storage key with the user's master cross-signing key is no
  longer required.  The key is trusted on the basis of the user entering the
  key/passphrase.


## Potential issues

Users who have data stored using the old encryption algorithm will need their
data migrated.  Clients that support the old algorithm but not the new
algorithm will not be able to use the migrated secrets until they are updated
with the new algorithms.  This should not be a major problem because the only
clients that are known to have implemented the old algorithm are Riot
Web/Android/iOS, and they have been upgraded to implement the new algorithm.


## Alternatives

Rather than switching to a symmetric encryption algorithm, we could stay with
an asymmetric encryption algorithm, and add on a method to authenticate the
data.  However, it is much safer to use well-known cryptographic methods rather
than trying to invent something new.  Since the main reason for using an
asymmetric scheme was to ease migration from older key backups without
requiring the user to re-enter the key, but this is no longer possible due to
the need to authenticate the data using the Secret Storage key, there is no
reason to stay with an asymmetric algorithm.  It is also better to use
cryptographic methods already used in Matrix where possible, rather than
introducing something new.
