Secure Design Review Case Study : Ente

I routinely get messages on LinkedIn and Twitter asking how to prepare for threat modeling and security system design review interviews. There is a ton of material for software engineering system design material, but there’s a distinct lack of similar material for security engineering. My goal is to analyze complex and real world systems that have available architecture with a focus on security engineering. This blog aims to assist new comers navigate system design interviews by providing a breakdown of the service architecture similar to that of Ente.

Note that this blog only focuses on the design and implementation of cryptographic systems. It does not deal with over all system architecture such as which database to use, how to authenticate and authorize users, how to ensure that the client applications are secure, and how to secure the cloud infrastructure required to support all of the features.

Case Study

Ente is a photo management service similar to Apple or Google photos. Ente allows a user to securely upload and store photos either in Ente-hosted or self-hosted environments. Ente has done an excellent job of sharing the intricate details of their system architecture with a focus on security and privacy aspects. Let us pretend to analyze security properties of a similar system in the context of an interview/study session and compare it with Ente’s implementation.

Security Design Principles

Let’s start with some of the principles which will guide our design

  1. Since the privacy of user uploads is critical in our architecture, we must use client-side encryption and never share the plaintext encryption keys with our servers. This will ensure that our operators can never decrypt the user uploaded content thus providing confidentiality and privacy.
  2. We want to ensure that user uploads are untampered both during transit or at rest. Hence, we want an encryption scheme which provides the system with strong data authenticity/integrity properties.
  3. Unique encryption key for each user to achieve better isolation and reduce the blast radius in case of a security incident.
  4. The encryption scheme should be efficient and ensure that massive quantities of user uploads can be encrypted. We must use encryption algorithms supported by multiple platforms such as Web, Android, iOS.
  5. In order to guarantee secure file sharing with different users, unnecessary and broadly scoped encryption keys should not be exposed.
  6. In case of a password compromise, there should be a mechanism to rotate the encryption key.
  7. We will only use well understood cryptographic constructions. All the cryptographic operations must be performed through a well established library.

Generating Encryption Keys

Symmetric key cryptography is generally more efficient for performing encryption/decryption on massive quantities of data. So, we need to generate encryption keys to use in our symmetric encryption scheme with Authenticated Encryption (AEAD) support.

We can randomly generate an encryption key using our chosen library and use that encryption key to encrypt user contents. However, we want to be able to view photos on Web client, Android, iOS clients. These various devices will require a plaintext encryption key to decrypt the user contents so that the user uploads are visible on all the devices. This violates our first design principle of not sharing plaintext encryption key anywhere in our system.

To avoid the above issue, we will derive an encryption key from the user password. As the encryption key is generated from user password, there is no need to save the plaintext encryption key anywhere in our system. We will use a well known cryptographic construction named Key Derivation Function (KDF). The KDF will take user password, salt, and an iteration count as inputs and will return a securely generated encryption key. The salt will be uniquely generated and will ensure that even if 2 users use the same password, the generated encryption key will be different for them. A higher iteration count parameter will thwart any brute force attempts to derive encryption key by attacker. We could use this encryption key derived from the user password to encrypt customer provided files.

This scheme covers design principles 1 and 3 from the above list.

  • User data must be encrypted client-side with encryption key securely derived from user password. Since the encryption key will not be shared with our servers, the user data will not be accessible to anyone including our operators.
  • Deriving an encryption key from the user password ensures that each user’s data is encrypted with a unique encryption key and will meet our isolation and blast radius guarantees.

Ente Encryption Key Generation

Now let’s compare this to the architectural information Ente has published. Ente is using the Libsodium library which supports well understood cryptographic constructions and it is well tested. As such, it meets our 7th design principle

  • We will only use well understood and trusted implementation of these constructions.

Copied from Ente's architecture blog

As we can see, the keyEncryptionKey is derived from the user password using Argon2 which is the default KDF function in Libsodium. Additionally, there are some benefits to using Argon2 such as better resistance against side channel attacks, ability to increase CPU and memory requirements, as discussed in this StackExchange post. After running user password through the Argon2 KDF, we will have a securely generated encryption key.


Key Encryption Key

The encryption key we derived above is completely dependent on the user password. If the user changes their password, the encryption key we derived before will no longer work. As we are not storing the derived encryption in plaintext, all the data encrypted with the encryption key will be completely inaccessible which is our worst case scenario. So we will not use the encryption key derived from user password to directly encrypt the user uploads. Also we will rename the encryption key derived from user password to Key Encryption Key (KEK)

As we don’t want to directly encrypt user uploads with KEK, we will generate a new cryptographically random encryption key (data encryption key), and use this data encryption key for encrypting the user uploads. We can use our KEK (derived from user password) to encrypt the data encryption key. The encrypted version of the data encryption key can be then shared with our server as well as all of user devices without compromising our confidentiality properties.

So the steps are

  1. Derive an encryption key from user password called key encryption key (KEK)
  2. Securely generate a new encryption key called data encryption key
  3. Use the data encryption key to encrypt the contents of user uploads
  4. Use the KEK key to encrypt the data encryption key, and then we can safely store the encrypted data encryption key on our servers. The KEK will not be stored anywhere in our systems and user is expected to enter correct password each time to derive KEK correctly.

Note that this pattern is known as Envelope Encryption and it is widely used including AWS KMS and 1Password. It is an incredibly useful pattern for interviews as well as designing systems. Utilizing KEK helps us achieve our 6th design principle.

  • In case of a password compromise, there should be a mechanism to rotate the encryption keys

Ente Implementation

Ente calls our data encryption key as master key in their architecture. During registration a new encryption key is generated which is used for actual data encryption. This master key is then encrypted with our KEK and stored on Ente servers, as well as propagated to other devices owned by the same user.

Note : At this point, Ente creates a few more encryption keys for each album and each file. For the purposes of our secure design case study, it isn’t too important and we will skip those steps. However, creating file or collection specific keys help us in reducing blast radius even more.

Data Encryption

As we need to encrypt large amounts of data, we are going to use symmetric key encryption algorithms. Additionally, as we want data confidentiality as well as data authenticity, we need to use a scheme which supports Authenticated Encryption.

Our chosen library Libsodium provides 2 constructions for Authenticated Encryption

  1. AES GCM
  2. XSalsa20 for encryption with Poly1305 MAC for authenticity

Either of these choices satisfy following design principles

  • Support for efficient encryption of large amounts of data
  • Data authenticity /integrity guarantees for the user uploads

Ente’s Implementation

Ente uses XSalsa20 stream cipher for encryption and Poly1305MAC for data authenticity(integrity) which are the defaults provided by Libsodium library. Utilizing XSalsa20 over AES variants has some additional benefits such as consistent performance even without hardware support (which is harder to predict when we want to support Android devices), not vulnerable to nonce reuse (which is AES GCM is vulnerable to), and implementation safety against side-channel attacks etc.

File Sharing

In this day of social media and online backups, there is an expectation that files will be shared with someone else. As we know symmetric key cryptography is great for encrypting and decrypting data efficiently. However, symmetric key cryptography is not great for sharing files with other parties as sharing symmetric keys between participants is not possible without disclosing the symmetric key, thus weakening the crypto system. There is no easy way to share our data encryption key with other users in our system unless we utilize Assymetric key cryptography.

To support file sharing use cases, we will create a public and private key pair for each user during user registration. We must generate the private and public key pairs on the user device to maintain our confidentiality design principle. We will encrypt the private key with the key encryption key before uploading it to our servers or propagating this key to different user devices. We will store the public key as it is on our server with some kind of user identifier. This mapping will allow us to fetch a public keys for relevant user during file sharing workflow.

This mechanism helps us meet our design principle of

  • Secure file sharing must be possible. File sharing should not expose unnecessary encryption keys with the receiver.

Ente File Sharing

Ente follows similar approach outlined above. Per user, private and public key pairs are generated on user device with Libsodium library. Encrypted versions of the private keys along with public keys are then propagated to the Ente servers. When a user wants to share a file with someone, the associated file encryption key is fetched, and decrypted using user’s data (master key) encryption key. The file encryption key is again re-encrypted with the public key of the receiver, and the encrypted file encryption key, along with the encrypted file is sent to the receiver. Receiver can use their private key to decrypt the file encryption key, and then decrypt the shared file using decrypted file encryption key.

Secure Key Generation

By utilizing Libsodium’s Key Generation we can satisfy our design principle of

  • All the cryptographic operations must be performed through well trusted library.

Verification

The design documented meets all of our design principles. However, as a security engineering/architect our job is not done yet. We still need to ensure that the implementation correctly peforms all the cryptographic operations as well as ensure that there are no other security flaws in the implementation. Ente partnered with a 3rd party pentest firm to verify that the implementation is secure and meets all the security controls. Once we pentest the implementation, we have to perform source code review, identify all the security issues, mitigate/risk accept all the findings, we can present evidence that the system is behaving as designed.

However, our job is never done. We haven’t create a holistic threat model which looks at other assets such as other user data like email and password, our cloud environments, our mobile applications, and our Web application. There are other areas which we didn’t cover such as user AuthN/AuthZ, Employee AuthN/AuthZ, Safety of our build systems, safe delivery of our Web and mobile applications to end user. But at the same time no one person could perform all these tasks and no 1 book (let alone a blog post) can cover it all. I hope you all learned something new today and I wish you best of luck in your security engineering career.

Appendix

Although our KDF function is secure, humans are inherently bad at creating complex and unguessable passwords. As we saw in the case of LastPass vaults, there is always a risk that an attacker could brute force an insecure password set by a user. 1Password has a different design where an additional secret key is used in combination with the user password to derive KEK key. However, for Password manager it is possible to ask users to store this secret key somewhere safe. I am not sure if we should use a similar scheme in a photo management application.

Adhiran Thirmal

Solutions Engineer at Cycode | Ex-AWS

10mo

Thanks for sharing this Pushkar!

Sten Sjöberg

Founder/CEO @ Remy (YC S23)

10mo

Love to see this type of content! Pushkar Jaltare I'm curious how you arrived at the design principles at the top (almost non-functional requirements) and how you drove those requirements against all the other non-security requirements I'm sure competed for mindshare? In a way the most important step

Like
Reply
Noah Little

The only CSM coach who ACTUALLY IS A CSM (not retired) • I help underpaid and laid off CSM's get Customer Success Jobs WITHOUT networking via my F.I.R.E framework 🔥 • $10.1M in Salary • 101 success stories 🎉 Proof 👇

10mo

That sounds like a valuable initiative! Pushkar Jaltare

To view or add a comment, sign in

More articles by Pushkar Jaltare

Insights from the community

Others also viewed

Explore topics