Back to Blog
Security en

How Journai Encrypts Your Data End to End

Journai stores some of the most sensitive data you have: vaccination records, passport details, allergies, medical conditions. We say this data is end-to-end encrypted, and in this post I want to show what that means in practice. Which keys exist, where they are stored, what our server can see and what it cannot. I will also cover the one feature where data is decrypted on the server, because a security claim is only useful if it is honest about its limits.

A padlock on a laptop keyboard Photo: Unsplash

The short version

  • Your data is encrypted on your phone before it is uploaded, with a key our server never sees in plain form.
  • That key is protected by an encryption password that never leaves your device.
  • Our server stores encrypted blobs. Without your password, they are unreadable to us and to anyone who gets access to the server.
  • The exception is the optional AI scan, where an image is decrypted on the server for a moment so it can be analysed.

Two keys: the data key and your password

When you set up encryption, the app does two things on your device.

1. It creates a data key. This is 32 random bytes from the system's secure random number generator. Everything you store in Journai is encrypted with this key.

2. It protects the data key with your password. Your password is turned into a second key using PBKDF2 with HMAC-SHA256 and a random 32-byte salt. PBKDF2 is a key derivation function: it deliberately makes each password guess expensive, so an attacker cannot simply try millions of passwords per second. The derived key then encrypts the data key with AES-256-GCM.

Only the result of step 2 is sent to our server: the salt, the nonce and the encrypted data key. This is often called key wrapping. The password itself is never transmitted, and neither is the unwrapped data key.

Why two keys instead of encrypting everything directly with the password? Because it makes changing your password cheap. When you pick a new password, the app wraps the same data key again with a new salt and uploads the new wrapped key. None of your actual records need to be decrypted or re-encrypted.

Encrypting a record

Each entry, for example a vaccination or a passport, is serialised to JSON on your device and encrypted with AES-256-GCM using the data key. Every encryption uses a fresh random 12-byte nonce, and GCM adds a 16-byte authentication tag.

The tag matters as much as the encryption itself. AES-GCM is authenticated encryption: if someone changes even a single bit of the stored ciphertext, decryption fails instead of returning manipulated data. So the server cannot quietly alter your records either.

What gets uploaded per entry is the ciphertext plus a label for the type of entry, such as "vaccine" or "identity document". The app needs that label to load the right entries for each screen.

Signing in on a new phone

When you sign in on a new device, the app downloads your wrapped data key and asks for your encryption password. The password is run through PBKDF2 again with the stored salt, and the result unwraps the data key locally. If the password is wrong, the GCM tag check fails and the app tells you.

Once unlocked, the data key is kept in the platform's secure storage: the Keychain on iOS and encrypted storage backed by the Android Keystore on Android. The offline copy of your data on the phone is stored encrypted as well and is only decrypted when you open it.

What our server can see

End-to-end encryption does not mean the server knows nothing. To be precise, our server knows:

  • your account details (email address or phone number, linked Google or Apple account)
  • which types of entries you have and how many, for example three vaccines and one passport
  • the size of each encrypted entry
  • your IP address in server logs, which are deleted after 7 days

What it cannot see is the content: no vaccine names or dates, no passport numbers, no allergies, no conditions.

What happens if you forget your password

Then your data is gone. This is not a policy decision, it is a direct consequence of the design. We do not have your password or your data key, so there is nothing we could use to recover it. The app warns about this when you set up encryption. You can reset encryption, which deletes the encrypted data and lets you start over.

If this sounds harsh: it is the same trade-off every end-to-end encrypted service makes. A recovery option run by us would also be a way in for anyone who compromises us.

The exception: AI scans

Journai can read a photo of a vaccination record, passport or insurance card and fill in the fields for you. Text recognition at this quality needs a large model, and we use Google Gemini for it. That means for this feature, the image has to be readable on the server for a moment.

Here is how that works:

  1. At sign-in, your phone creates a fresh X25519 key pair and the server creates its own. Both sides combine their private key with the other side's public key (an elliptic-curve Diffie-Hellman key exchange) and run the result through HKDF-SHA256 to derive the same transfer key.
  2. The app encrypts the image with AES-256-GCM under this transfer key and sends it, on top of the normal HTTPS connection.
  3. The server decrypts the image in memory, sends it to Gemini, overwrites the image bytes, and encrypts the extracted fields back to your phone with the transfer key.
  4. Your phone decrypts the result, you review it, and the entry is then encrypted with your data key like any other entry before it is stored.

The image is never written to our database. Still, during a scan our server and Google can see the image, so the scan is not end-to-end encrypted. That is why it is optional, it asks for your explicit consent first, and you can always type the details in yourself instead. You can withdraw the consent at any time in the settings.

Sharing your emergency card

The emergency card is built on your phone and shared through your phone's normal share menu. It does not go through our server. Keep in mind that once you send it to someone, it is a normal image on their device.

The building blocks

Journai does not use any home-made cryptography. Everything above is built from standard, well-studied primitives:

Purpose Algorithm
Encrypting data and keys AES-256-GCM
Deriving a key from your password PBKDF2-HMAC-SHA256
Key exchange for scans X25519
Deriving the transfer key HKDF-SHA256

On the phone we use the cryptography_plus library for Dart, and on the server the Java cryptography API and Bouncy Castle.

If you have questions about this or think we got something wrong, write to us. You can find the contact details on our support page.


Sources

Last updated: October 2026.