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
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.
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
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
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.
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.
Recommended by LinkedIn
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
Either of these choices satisfy following design principles
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
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
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.
Solutions Engineer at Cycode | Ex-AWS
10moThanks for sharing this Pushkar!
Founder/CEO @ Remy (YC S23)
10moLove 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
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 👇
10moThat sounds like a valuable initiative! Pushkar Jaltare