Where does a secret actually go?

Every value, and the exact formula behind it — nothing left unexplained

PREPARE 1. Write the secret The plaintext message, typed by the sender — nothing sent yet 2. Generate five raw values Message ID · URL Secret · Challenge Secret · KDF Salt · IV — all random 3. Derive two keys from those values Encryption Key = HKDF-SHA-256(URL Secret + Challenge Secret, KDF Salt) Authentication Key = HKDF-SHA-256(same 3 inputs, different label) 4. Encrypt the message Ciphertext = AES-256-GCM(message, Encryption Key, IV) 5. Compute the proof Proof = HMAC-SHA-256(Authentication Key, Message ID) SEND & STORE 6. Send to the server Sends: Message ID, Ciphertext (step 4), IV, Proof (step 5) — nothing else 7. Store the record Server saves exactly those four values it just received, nothing more 8. Confirm saved Server replies with success only 9. Show link + Challenge Key Link holds Message ID, URL Secret, KDF Salt — Challenge Key shown separately Link and Challenge Key travel separately — time passes REVEAL 10. Open the link Message ID, URL Secret, KDF Salt all come straight from the link 11. Enter the Challenge Key The one piece the link didn't already contain 12. Derive the same two keys Encryption Key = HKDF-SHA-256(URL Secret + Challenge Secret, KDF Salt) Same formula as step 3 — matches only if the Challenge Key was correct 13. Compute the proof, again Proof = HMAC-SHA-256(Authentication Key, Message ID) Same formula as step 5 14. Send one request Sends: Message ID + this Proof (step 13) — nothing else VERIFY 15. Compare, then delete Compares against the Proof stored in step 7 — a match deletes it instantly 16. Decrypt and show, once Message = AES-256-GCM-decrypt(Ciphertext, Encryption Key, IV) Ciphertext and IV are what the server just returned