KeyAuth
Sign in

Writing your own client

The protocol is fully specified, so you can implement a client in any language that has AES-GCM, HMAC-SHA256 and HKDF.

What you need

  • AES-256-GCM with associated data
  • HMAC-SHA256 and SHA-256
  • HKDF-SHA256 (extract and expand)
  • Base64, hex, a JSON parser, raw deflate inflation
  • A cryptographically secure random source for nonces and IVs

Python, Go, Rust, C# and Node all cover this from their standard library or one common package. Read the KA1 protocol for the exact construction first.

Implementation checklist

  1. Build the payload {"a": action, "p": {…}}.
  2. Generate a fresh 12 byte nonce and 12 byte IV per request. Never reuse an IV with the same key.
  3. Derive the request salt, then encKey and macKey with dir = "c2s" and an empty binding.
  4. Build the associated data string with 0x1f separators, in the documented field order.
  5. Encrypt, then sign aad 0x1f ivHex 0x1f ctBase64.
  6. POST the envelope.
  7. For the response, derive with dir = "s2c" and the binding set to your raw request signature.
  8. Verify the response signature and GCM tag before parsing anything out of it.

The mistakes that will bite you

  • Treating an unsigned response as success. Failures before decryption are plaintext. Anything without a valid signature must be a hard error, no exceptions.
  • Parsing before verifying. Verify the tag and signature first, always.
  • Forgetting the response binding. If you derive response keys without mixing in the request signature, responses become replayable.
  • Reusing nonces. The server refuses repeats with REPLAY_DETECTED, and IV reuse under one key breaks GCM outright.
  • The session id on init. The reply to init is keyed with the empty request session id; the new id arrives inside the payload. Do not try to use it for that response.
  • Byte order in the salt. Fields are separated by a single 0x00 byte, and the associated data uses 0x1f. Mixing them up produces a valid looking BAD_SIGNATURE loop.

Test vectors

Do not debug against a live server. The repository ships cross language vectors covering SHA-256, HMAC, HKDF at 32 and 48 bytes, and AES-GCM with associated data:

bash
php sdk/cpp/tests/vectors.php

Match those byte for byte first. They are the same vectors the C++ SDK is verified against, so if your output matches, your primitives are correct and any remaining failure is in your envelope construction.

File download

Call file.chunk with {"key": "core", "chunk": 0}, read the metadata from the first response, then fetch the remaining chunks. Concatenate in order, inflate if compression is deflate, then check the length and SHA-256 against the metadata. Do not hand a payload to your caller before that check passes.