Carlo is built on a simple, slightly stubborn promise: the data you put into it is yours, and the company that runs it can’t read it. Your records are locked in a way that leaves us holding nothing but sealed boxes.

That promise gets interesting the moment two people want to share. CoCarlo lets a couple keep a shared financial life together, and the obvious question is: if you and your partner can both open the shared data, and it all lives on our server, how is it still true that we can’t open it?

Here’s the whole answer, first in plain language, then, for the people who want to see the actual mechanism, in technical terms.


The plain version: one key, two safes

Picture a shared house. Everything you and your partner track together lives inside it, and there’s a single key that opens it.

Both of you need a copy of that key. The trick is getting a copy to each of you without ever leaving one lying around where someone else could grab it.

So each person has their own personal safe. A safe with a one-way slot on top: anyone can drop something in, but the only way to take something out is to open the safe with your own private combination, which only you know.

Sharing works like this:

  1. Alice’s phone creates one shared key. That key locks and unlocks all of the shared data.
  2. It makes two copies.
  3. It drops one copy through the slot in Alice’s safe, and one copy through the slot in Bob’s safe.
  4. Neither copy can be pulled back out through the slot. The only way out is to open the safe.
  5. Alice opens her safe with her private combination and takes out the key. Bob does the same with his.
  6. Now both of them can open and update the same shared data.

The server stores both locked safes and the locked shared data. It doesn’t know either private combination, so it can’t open the safes, and it can’t read the data.

That last part is the whole point. The server holds everything and can open nothing. A break-in, a subpoena, or a curious employee gets a pile of locked safes and a pile of locked data, and no way into any of it.

Infographic titled CoCarlo Sharing: One Key, Two Safes. Nine numbered steps show Alice and Bob sharing a budget: Alice’s phone creates one shared room key, copies it twice, and drops one copy into each person’s safe through a one-way slot. Each person opens their own safe with their own private combination to retrieve the key. A footer shows the server stores both locked safes and the encrypted data but cannot open either safe, see either combination, get the shared key, or read the data.
One shared room key. Each person has their own safe. The server stores the safes and the encrypted data — it cannot open anything.

One more thing that falls out of this design for free: because each person has their own safe, one person leaving never locks the other out. Your copy is yours. And adding a third person later is just one more safe, no need to disturb anything that already exists.

If that’s the level of detail you wanted, you’re done. You now understand how CoCarlo sharing keeps your data private. The rest of this post is for the people who want to see what the safes and combinations actually are.


The technical version: per-recipient key wrapping

Everything above is a metaphor for a standard, well-understood pattern in cryptography. Here’s the translation.

What the metaphor represents

The shared room key is the shared CoCarlo DEK (data encryption key): a symmetric key used to encrypt and decrypt the shared data.

The shared room is the encrypted CoCarlo dataset: transactions, journal entries, photos, and any other records belonging to the shared account.

The personal safes are not containers. Each safe is a separately encrypted copy of the shared DEK. There is one shared DEK, but the server stores two wrapped versions of it:

shared_dek_wrapped_for_alice
shared_dek_wrapped_for_bob

Both wrap the same underlying DEK. They’re encrypted differently because each is intended for a different person.

The one-way slot is a public key

A safe’s one-way slot is a user’s public key.

Alice can use Bob’s public key to encrypt the shared DEK for Bob. She never needs Bob’s private key to do it:

bob_wrapped_dek = encrypt_with_bobs_public_key(shared_dek)

Bob’s public key can sit on the server and be handed to anyone. Knowing it lets you encrypt something for Bob; it does not let you decrypt anything meant for Bob. That’s exactly why the slot is public: anyone can put something securely into Bob’s safe, and no one but Bob can take it out.

The private combination is a private key

Bob’s private combination is his private key. Only Bob’s device has it. It lives in the device’s secure keystore and is never sent to the server. His device uses it to unwrap his copy of the DEK:

shared_dek = decrypt_with_bobs_private_key(bob_wrapped_dek)

Alice has her own independent keypair and does the equivalent with her own wrapped copy.

Why there are two safes

A DEK wrapped for Alice can’t be decrypted by Bob, because they hold different private keys. So the shared DEK is wrapped once per member:

alice_wrapped_dek = encrypt_with_alices_public_key(shared_dek)
bob_wrapped_dek   = encrypt_with_bobs_public_key(shared_dek)

Same DEK inside both. Only the outer encryption differs. This pattern is usually called per-recipient key wrapping, or envelope encryption.

What the server stores, and doesn’t

The server stores:

encrypted_shared_data
alice_wrapped_dek
bob_wrapped_dek
alice_public_key
bob_public_key

The server does not store:

the raw shared DEK
Alice's private key
Bob's private key

Because it holds neither private key, it can’t unwrap either copy of the DEK. Because it can’t obtain the DEK, it can’t decrypt the shared data. The inability is structural, not a policy we promise to follow.

What actually happens when Alice opens CoCarlo

  1. Her device downloads her wrapped DEK.
  2. It retrieves her private key from the secure keystore.
  3. It unwraps the shared DEK locally.
  4. It decrypts the shared data locally.
  5. When she changes something, the device re-encrypts it with the same shared DEK before sending it back.

Bob does the same, independently, with his own wrapped DEK and private key. Neither person depends on the other being online.

Adding another member

To add Charlie, an already-authorized device gets Charlie’s public key and creates one more wrapped copy:

charlie_wrapped_dek = encrypt_with_charlies_public_key(shared_dek)

The shared data is never re-encrypted. The system just adds one more authorized route to the same DEK.

The whole architecture in three lines

one shared symmetric key
+ one asymmetric wrapper per member
+ zero server-side decryption capability

CoCarlo encrypts shared data with a single symmetric DEK, then stores a separately wrapped copy of that DEK for each authorized member, encrypted to that member’s public key. Each member unwraps their copy locally with their private key. The server is a place that stores sealed things and can open none of them.


That’s the design. The metaphor and the mechanism are the same idea at two resolutions, and both are true: one shared key, one personal safe per person, and a server that holds everything and opens nothing.