One Key to Open Them All: Master Key Decryption with Homomorphic Encryption

Every company that encrypts its data eventually faces the same awkward moment: the person who held the key is gone. An employee leaves, a laptop is stolen, a phone falls into the sea, and everything encrypted with that person’s key becomes unreadable forever. The obvious fix, one company-wide key for everybody, is worse: then every employee can read every other employee’s data. What we really want is what hotels have done for decades. Every guest gets their own room key, which opens only their own room, while the manager holds a master key that opens every room in the building.

Darth Vader by pexels

In this post, we’ll build exactly that with homomorphic encryption: every user encrypts with their own key pair and decrypts only their own data, while an authority holding a master key can decrypt the data of all users. We’ll use LightPHE in Python, Go, Java and TypeScript. And since a master key is, by design, a key that reads everything, we’ll also be honest about when you should and shouldn’t build one.


🙋‍♂️ You may consider to enroll my top-rated cryptography course on Udemy

Public Key Cryptography From Scratch

How It Works: Two Trapdoors in One Ciphertext

The cryptosystem behind this is Bresson-Catalano-Pointcheval (BCP), from A Simple Public-Key Cryptosystem with a Double Trapdoor Decryption Mechanism and Its Applications (ASIACRYPT 2003). You can think of it as a mix of two old friends: it encrypts like ElGamal, but it lives in the same modular world as Paillier.

authority:   n = p * q, the product of two secret safe primes, and a generator g
             publishes n and g, and keeps p and q as the master key

user:        picks a secret a as its own private key
             publishes h = g^a mod n^2 as its own public key

encrypt m:   A = g^r mod n^2
             B = h^r * (1 + m n) mod n^2          for a random r

Such a ciphertext can be opened in two independent ways:

  • The local trapdoor, the user’s own key. A user who knows a computes A^a = g^(ar) = h^r, so B / A^a = 1 + m n, and reading m from that is trivial. This is plain ElGamal-style decryption.
  • The master trapdoor, the factorization of n. The authority doesn’t know a or r. But knowing p and q, it can compute discrete logarithms modulo n in this group—the same trick that makes Paillier decryption work. So it recovers a mod n from the user’s public key h, and r mod n from A, which is enough to strip the mask off B and read m.

Everybody else is stuck: another user doesn’t know a, and doesn’t know the factorization of n either. The most elegant part is how users get their keys. A user needs only the authority’s public key, n and g, to generate a key pair, so the authority never sees, stores or hands out anyone’s private key—and still can open every ciphertext. The escrow lives in the math, not in a database of copied keys.

Required Cryptographic Features

1. A double trapdoor. The same ciphertext must be decryptable both with a per-user secret and with a single master secret, and the two must be independent: knowing your own key must not help you find the master key, or anybody else’s key.

2. Shared public parameters with self-generated user keys. All users build their keys on top of the authority’s public n and g, with the public key alone. That’s what lets one master key open them all, while every user’s private key stays on the user’s own device.

3. Homomorphism that both trapdoors understand. BCP is additively homomorphic and supports multiplication with plain constants, like Paillier. A user can add up their own ciphertexts, e.g. monthly expenses into a total, and both the user and the master key decrypt the result. One subtlety: this works within the ciphertexts of a single user. Each user masks with their own h, so adding Alice’s ciphertext to Bob’s produces garbage that nobody can decrypt—not even the master key. LightPHE doesn’t stop you from doing it, so be careful.

4. A carefully generated modulus. The master trapdoor needs p and q to be safe primes, and g to have the largest possible order. LightPHE takes care of this when the authority generates its keys, in about half a second for a 1024-bit key on my laptop.

Which Algorithms Can Be Used, and Why

Out of the more than 25 cryptosystems in LightPHE, only Bresson-Catalano-Pointcheval supports master key decryption. I asked the others for user keys, and LightPHE refused each of them with does not support generating user keys sharing a master key. The reason is that the others have a single trapdoor:

AlgorithmsMaster key decryptionWhy
Bresson-Catalano-Pointchevalâś…Two independent trapdoors: a discrete logarithm per user, and the factorization of n for the authority
Paillier, Damgard-Jurik❌The only trapdoor is the factorization of n. If users shared one n, whoever can decrypt one user’s data can decrypt everybody’s, so there is no room for personal keys
ElGamal, Exponential ElGamal, Elliptic Curve ElGamal❌Every user can have a personal key in a shared group, but discrete logarithms are hard for everybody, including any would-be authority, so there is no master trapdoor. BCP fixes exactly this by moving ElGamal into a group where the factorization makes discrete logarithms easy for the authority
RSA and the others❌A single trapdoor per key pair, so a master key would have to be a copy of every user’s private key

That last point is the naive alternative, and it works with any algorithm: the authority generates every user’s key pair and keeps a copy of each private key. But then the authority stores thousands of private keys instead of one, has to be online for every new user, and knows every key from day one. With BCP, the authority keeps a single secret, ideally offline, and users generate their own keys without ever talking to it.

Example 1: Employees and Their Company

A company publishes its public key, and every employee generates their own key pair from it. Employees encrypt their expense claims with their own keys, and add them up homomorphically. Each employee reads only their own claims, and when an employee leaves, the company can still read theirs with the master key.

Note what Alice gets when she tries to decrypt Bob’s claims: not an error, but a meaningless number hundreds of digits long. Her key simply doesn’t fit his lock. When she reaches for the master key, LightPHE refuses, because her private key has her own trapdoor a only, not p and q. Java snippets use assert for brevity, so run them with -ea to enable assertions.

Example 2: Recovering a Lost Key

A savings app lets its users keep their data encrypted on their own phones. Bob encrypts his monthly contributions to three savings goals, and projects them over a year with homomorphic multiplication. Then Bob drops his phone into the sea, and his private key goes with it. After Bob proves his identity, the app recovers his data with its master key, and Bob starts over with a fresh key pair.

Amounts are kept in cents, as integers, which is a good habit for money anyway. The master key decrypts the result of homomorphic operations just like the user’s own key does, so the app recovers the yearly projections, not only the raw contributions. Master key decryption works on encrypted tensors as well, and it’s cheap: about 57 milliseconds per ciphertext with a 1024-bit key on my laptop, against 22 milliseconds with the user’s own key.





Master Key vs Splitting a Key Into Pieces

In our previous post, we split a private key into pieces, so that any 3 of 5 directors could decrypt together. A master key is the mirror image of that idea:

Master key decryptionSplitting a key into pieces
ShapeOne key opens the data of many usersMany pieces are needed to open the data of one key
Who can decryptEach user alone, or the authority aloneOnly a quorum of shareholders together
Main riskThe master key holder reads everythingA quorum of colluding shareholders reads everything
Algorithms in LightPHEBresson-Catalano-PointchevalElGamal family, Paillier, Damgard-Jurik

It’s tempting to combine them, so that no single person holds the master key. LightPHE doesn’t support splitting a BCP key into pieces, so for now, protect the master key the old-fashioned way: keep it offline, e.g. in a hardware security module, and log every use.

More Scenarios

  • Employee offboarding: Employees encrypt their work files and figures with their own keys, so colleagues can’t read each other’s data, and the company doesn’t lose anything when someone leaves.
  • Account recovery: A consumer app keeps user data encrypted on devices, and offers recovery after a lost device without storing a copy of every user’s private key.
  • Regulatory retention: In regulated industries, firms must be able to produce records when auditors ask. Each department encrypts its own records, and the compliance office holds the master key.
  • Device fleets: Every sensor in a fleet encrypts its readings with its own key, so a compromised sensor exposes only its own data, while the manufacturer can still decrypt any device’s readings for diagnostics.

Caveats

  • A master key is a backdoor by design: Whoever holds it reads everything, and users can’t opt out once their keys are built on the authority’s parameters. That’s fine when users know and agree, as in a company or a recovery feature they signed up for. It’s not fine as a hidden backdoor, and the history of key escrow proposals, such as the Clipper chip of the 1990s, shows how controversial forced escrow is. Be transparent about it.
  • One secret to rule them all: If the master key leaks, every user’s data is exposed at once, and new user keys don’t help, since they are built on the same n. Protect it accordingly, and plan how you would rotate to a new authority key.
  • Don’t mix users’ ciphertexts: Homomorphic operations work within a single user’s ciphertexts. Adding ciphertexts of different users produces garbage, silently.

Conclusion

Master key decryption gives every user a key of their own, and an authority a key to all of them, just like the rooms and the master key of a hotel. Bresson-Catalano-Pointcheval makes this possible with two independent trapdoors in the same ciphertext: a discrete logarithm that belongs to each user, and the factorization of a shared modulus that belongs to the authority. Users generate their own keys from the authority’s public key alone, so the authority never holds anybody’s private key, yet it can still decrypt everybody’s data, including the results of homomorphic operations.

Used openly, that’s a clean answer to lost keys and departing employees. Used quietly, it’s a backdoor. The math is the same either way, so the responsibility lies with whoever holds the master key—and with LightPHE, it takes only a few lines of Python, Go, Java or TypeScript to build.


Support this blog financially if you do like!

Buy me a coffee      Buy me a coffee


Leave a Reply