This article documents ProtonCalendar’s security model and illustrates how our product protects calendar-related sensitive data. We examine the advantages and limitations of our approach.
This document is somewhat technical, discussing how encryption protects the different layers of data. Still, it is meant to be accessible to a general audience and attempts to explain how ProtonCalendar works in plain language.
ProtonCalendar is an online calendar that is integrated within the Proton suite of products. It is designed to deliver the convenience of a calendar app with the security and privacy of a Proton product. When developing ProtonCalendar, we knew it had to support the following features:
- Send and receive event invitations, both from other ProtonCalendar users and non-Proton users
- Send and receive event updates
- Add attendees to an event
- Add reminders to an event
- Support multiple calendars
- Share an event between multiple calendars
- Share calendars
The goal is to prevent the server or any adversary that gains access to the server from accessing sensitive user data. They must not be able to:
- Access the private content of events
- Modify the public content of events undetected
- Forge an event on behalf of an existing member of a calendar
- Add a member to a calendar.
At its most basic, a calendar is just a collection of events. It would be a relatively easy task to secure such a calendar app with encryption. However, to be useful, a calendar should let you share an event with other users and across multiple calendars. You may also want to share your calendar with other users. These interactions are what make encrypting ProtonCalendar so tricky.
When you start using ProtonCalendar, you will join or create a calendar using one of your ProtonMail email addresses. You will become a member of that calendar, and your email address will be used as your identity within it. Any action you take, like creating, editing, or deleting an event, will be digitally signed using a primary address key that is linked to the ProtonMail address you used to join the calendar.
Each member will have a set of permissions that allow them to edit events, view event details, check availability, see the list of members, and invite new members.
For every calendar, we will generate a calendar key (for those interested, it will be an ECC Curve25519 PGP key). This calendar key will be used to encrypt the event data. (To see more details about the event encryption, skip down to the “Event encryption” section.)
This calendar key will then be symmetrically encrypted (PGP standard) using a 32-byte passphrase that is randomly generated on your device. Once it is encrypted, your calendar key will be stored on the ProtonCalendar backend server.
Each member of a calendar will have a copy of the same passphrase that is encrypted and signed using their primary address key. The signature ensures that no one, not our server or any third-party adversary, changed the passphrase. This is crucial because if an attacker could change a member’s passphrase, they could then modify the calendar key without the calendar members’ knowledge. This would allow the attacker to decrypt any new event created by the calendar’s members.
Thus a calendar is composed of:
- A Calendar Key with the corresponding passphrase
A member is a user, represented by an email address that is linked to the calendar and is composed of:
- An encrypted and signed passphrase
- A permission set
This allows multiple members to be part of the same calendar and share the same events without having to encrypt them with multiple keys.
You can share your ProtonCalendar with multiple Proton users. We implemented a secure invitation protocol that cryptographically guarantees that the user inviting you is who they say they are.
The calendar invitation cryptosystem
To invite a new member to your calendar, you need to grant them access to the calendar private key and make sure that they can decrypt it. This is the only way they would be able to decrypt and read the calendar’s events.
If you invite a new member, ProtonCalendar first has to fetch the invited member’s public key that is linked to their email address. Your ProtonCalendar client will then encrypt the calendar’s passphrase on your device using the invited member’s public key. The passphrase is then signed using your email address key.
The invited member, if they decide to join the calendar, can decrypt the passphrase using their address key. They can also verify that the signature on the passphrase belongs to your email address key. This lets the invited member cryptographically verify that you invited them. To accept the invitation, ProtonCalendar will then pin the passphrase for the invited member by replacing your signature with one created using their own email address key. This signature will later be used by the invited member to verify the passphrase at each application start.
A member with write-access can add a new event to a calendar.
Events have three types of data. They are:
- Shared event data, which is shared with all calendars that have that event
- Calendar data, which is specific to a calendar but shared with all a calendar’s members
- Member data, which is specific to a unique calendar and member
This division allows the main properties of an event to be shared between all calendars, while each calendar can have different comments for the same event. Furthermore, each member can set their own personalized alarms.
The shared event data that is the same on multiple calendars includes:
- Unique event identifier
- Start and end date of the event, repetition rule and date/time exclusions
- Description, summary (title), location
The calendar data that can be customized on each calendar includes:
And the member data that each member can customize includes:
All event data can also be split into two categories:
- Encrypted and signed properties
- Signed-only properties
Our server needs to be able to access some properties of an event so that it can retrieve and index the events efficiently. The properties that our server must access are the signed-only properties, which include:
- The start/end time of an event, along with its time zone information
- The repetition rule and the date/time exclusions
- The unique event identifier
- Time information for alarms
All the remaining properties will be encrypted and signed on your device before they are stored on our servers. In other words, all of an event’s critical information, like the title, description, location, and attendees, will be stored securely and privately with end-to-end encryption.
The event cryptosystem
An event’s encrypted data will be encrypted as a PGP message using the calendar private key. This data will also be signed as a PGP message using the author’s primary address key.
An event’s signed-only data will be signed as a PGP message using the author’s primary address key.
The signature of the data cryptographically ensures that each type of data was created and edited by the specified author and guarantees that nobody (not even ProtonMail) has tampered with your events.
When you create a new event, ProtonCalendar automatically takes the following actions to encrypt it:
- It generates two session keys. A session key is a random binary string of 32 bytes.
- Using the first session key, it encrypts the encrypted category of the shared event data. This session key is called the Shared Session Key.
- Using the second session key, it encrypts the encrypted category of the calendar and member data. This session key is called the Calendar Session Key.
- It then encrypts the Shared Session Key using the calendar private key. The result is called the Shared Key Packet.
- Next, it encrypts the Calendar Session Key using the calendar private key. The result is called Calendar Key Packet.
- Finally, the encrypted Shared Session Key and the encrypted Calendar Session Key are stored on the server along with the encrypted event data.
Sharing an event
As a ProtonCalendar user, you can invite anyone, including non-Proton users, to your event.
If you accept an event invitation from another user’s ProtonCalendar, then the event will automatically be added to your calendar and linked to the original event of the organizer. This way, if you or the organizer of the event update a shared component of the event (like the start time or location), the other user’s calendar will automatically be updated. They will be able to decrypt the new event data and verify the digital signature to ensure that the event modification was made by the claimed author.
The diagram below represents a single event. Some properties are shared across the calendars to which the event is linked, others are calendar level, and finally, some are member level as described in the “Event splitting” section.
Shared event encryption
Sharing an event with a different calendar is done by sharing the shared event data and shared event session key. Both calendars will access the same shared event data that is encrypted using the shared session key. Thus, if you want to share an event from your calendar to someone else’s calendar, you will have to send your shared session key (decrypted shared key packet) to the other user. The other user will use this shared session key to access the shared event data.
When the other user adds the shared event data into their calendar, their device will generate a new Calendar Session Key. It will use that new Calendar Session Key to encrypt any calendar data or member data from their calendar. The Shared Session Key received in the event invitation will be encrypted using the private key of the user’s calendar key and will be stored as a new Shared Key Packet.
Or, as this illustration shows, Shared Key Packet B will be different from Shared Key Packet A as Calendar Key A and B will be different. But the unencrypted Shared Key Packet A and unencrypted Shared Key Packet B will be identical and equal to the Shared Session Key.
The ability to send invitations to an event is an essential feature for every calendar. ProtonCalendar will support it with an added security layer. We decided to partially encrypt an event’s attendee list so that the email addresses of attendees cannot be accessed by ProtonMail or by any eavesdropper. This significantly enhances the anonymity of the participants.
To be interoperable with other email and calendar services, ProtonCalendar needs to allow external participants to respond to event invitations. We designed a system that enables RSVP updates from external users without the need to decrypt or sign any data. (This would be impossible as external users don’t have address keys or access to the calendar key.)
For each external attendee, ProtonCalendar generates a unique random token (a string of 40 random characters). This token is encrypted and stored along with the attendee’s email and attendee role. The user’s token is also stored unencrypted and unsigned along with their RSVP status to allow external updates.
This ensures that the attendee can respond to their invitation, even if they are an external user, and that the attendee list cannot be read from the event data.
At Proton, we’re committed to maintaining the highest levels of security and privacy through rigorously applied cryptography, while retaining a high level of usability. We are cognizant of the heightened security needs of many of our users who have entrusted their lives to us, and your protection and safety will always be our first priority.
To members of the Proton community, thank you for your patience and for affording us the time to properly build ProtonCalendar to meet the highest standards of security. We welcome all comments and feedback about ProtonCalendar’s security model via the bug report feature inside the app. ProtonCalendar is also eligible for our bug bounty program. Additionally, you can always reach us at firstname.lastname@example.org. Thank you for your support!
The Proton Team
This post was authored by Valentin Bonneaud and Daniel Huigens from the Proton team.
Interested in building products like this? Join us.
You can get a free secure email account from ProtonMail here.
We also provide a free VPN service to protect your privacy.