jonah.id

Zero Trust Stateless Secret Santa 🎅🥸

About

This is a zero-trust Secret Santa algorithm & implementation.

The goal is to create a single web page that can distribute assignments via out-of-band communications executed by the participants, with no server-side state, and no ability to alter or observe the results besides one's own.

This is done in three cycles:

  1. Accumulating a collection of public keys: each subject receives a hyperlink, which then gives them a hyperlink to send to the next subject. The new hyperlink contains a newly generated public key, the private key of which has been saved into a browser cookie. The public key is first encrypted with a public key provided by subject A. This prevents any agents from inferring key ownership by elimination. By the end of the cycle, all subjects have inserted their public key into the URL. This insertion is done in a securely random order to conceal key ownership from subject A.
  2. Assignment encryption: subject A uses its private key to decrypt all subject public keys. Each subject again receives a hyperlink, which generates a new hyperlink to send to the next subject. The new hyperlink contains the subject's own name, encrypted twice: once with the next shuffled subject's public key, and again with the public key proveded by subject A. This prevents any agents from inferring assignment origin by elimination. By the end of the cycle, every subject has inserted an assignment into the URL. This insertion is done in a securely random order to conceal key ownership from subject A.
  3. Assignment distribution: subject A uses its private key to decrypt all assignments. Each subject receives a hyperlink one final time, which includes all encrypted assignments. Each subject can decrypt only their own, shows the user their assiged name, and the same link to pass to the next subject. After this third cycle, everyone is aware of who they are assigned, and has no possible knowledge of any other assignments.

An extra layer of complexity is introduced by the ability for some agents to infer the ownership of a key. Specifically the second agent and the second-to-last agent can know who the first key's owner is and the last keys owner, respectively. This can be resolved by encrypting the public keys and the assignments with another public key, generated by the first agent. Only when all keys or assignments are added are they all decrypted by the first agent in the ring.


          +---+                         +---+                         +---+
          | A |                         | B |                         | C |
          +---+                         +---+                         +---+
            |                             |                             |
1. generate a wrapping key                |                             |
2. generate an assignment                 |                             |
   key                                    |                             |
3. save both private keys                 |                             |
   to cookie                              |                             |
3. encrypt assignment key                 |                             |
   with wrapping key                      |                             |
            |                             |                             |
            |------send B a URL with      |                             |
            |      wrapping key and       |                             |
            |      encrypted assignment   |                             |
            |      key------------------->|                             |
            |                             |                             |
            |                 1. generate an assignment                 |
            |                    key                                    |
            |                 2. save private key to                    |
            |                    a cookie                               |
            |                             |                             |
            |                             |---send C a URL with         |
            |                             |   wrapping key and          |
            |                             |   B's and A's assignment    |
            |                             |   keys--------------------->|
            |                             |                             |
            |                             |                  1. generate an assignment
            |                             |                     key
            |                             |                  2. save private key to
            |                             |                     a cookie
            |                             |                             |
            |                             |      send A a URL with------|
            |                             |      B's and A's and        |
            |<-----------------------------------C's assignment keys    |
            |                             |                             |
1. unwrap all assignment keys             |                             |
2. encrypt assignment for self            |                             |
3. re-encrypt with wrapping key           |                             |
            |                             |                             |
            |----send B a URL with        |                             |
            |    2x encrypted             |                             |
            |    assignment-------------->|                             |
            |                             |                             |
            |                  1. encrypt assignment for self           |
            |                  2. re-encrypt with wrapping key          |
            |                             |                             |
            |                             |----send C a URL with        |
            |                             |    2x encrypted             |
            |                             |    assignments for A & B--->|
            |                             |                             |
            |                             |               1. encrypt assignment for self
            |                             |               2. re-encrypt with wrapping key
            |                             |                             |
            |                             |     send A a URL with-------|
            |                             |     all 2x encrypted        |
            |<----------------------------------assignments             |
            |                             |                             |
1. decrypt all assignments                |                             |
   with wrapping key                      |                             |
2. decrypt own assignment                 |                             |
   with assignment key                    |                             |
            |                             |                             |
            |----send B a URL with        |                             |
            |    all decrypted            |                             |
            |    assignments------------->|                             |
            |                             |                             |
            |                    1. decrypt own assignment              |
            |                       with assignment key                 |
            |                             |                             |
            |                             |----send C a URL with        |
            |                             |    all decrypted            |
            |                             |    assignments------------->|
            |                             |                             |
            |                             |                     1. decrypt own assignment
            |                             |                        with assignment key
            |                             |                             |
            -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-

The source code can be found by right-clicking > View source, or in the Git repository here:
https://git.sr.ht/~jonahbron/jonah.id/tree/main/item/content/tools/secret-santa.html

The usage of shuffling/shifting is drawn from the Hannah Fry Numberphile video about Secret Santa.
https://youtu.be/5kC5k5QBqcc

Creative Commons License