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
- Build the payload
{"a": action, "p": {…}}. - Generate a fresh 12 byte nonce and 12 byte IV per request. Never reuse an IV with the same key.
- Derive the request salt, then
encKeyandmacKeywithdir = "c2s"and an empty binding. - Build the associated data string with
0x1fseparators, in the documented field order. - Encrypt, then sign
aad 0x1f ivHex 0x1f ctBase64. - POST the envelope.
- For the response, derive with
dir = "s2c"and the binding set to your raw request signature. - 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
initis 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
0x00byte, and the associated data uses0x1f. Mixing them up produces a valid lookingBAD_SIGNATUREloop.
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:
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.