Windows JSON protocol
This page describes every request and response of the Windows form. The types in win/src/protocol.rs
are authoritative.
Transport
- The service listens on one or more named pipes; without a configuration, on
\\.\pipe\wvds_crypto. For which pipes a configuration file opens, see Build features and configuration. - A request is exactly one line of UTF-8 JSON terminated by
\n. The response is also one line. You can send any number of requests in sequence over one connection. - Binary data is Base64 per RFC 4648 with padding (
=). - Several clients can be connected at the same time.
Common fields
Every request carries operation and request_id. You choose the request_id; the service echoes it
unchanged.
Every response to a parseable request contains:
| Field | Type | Content |
|---|---|---|
id | string | UUID the service assigns to the response |
request_id | string | from the request |
timestamp | number | time of the response, milliseconds since 1970-01-01 UTC |
success | boolean | true on success |
error | object | only on failure: code, message, optionally details |
duration_us | number | processing time in microseconds |
If the line isn't valid JSON or a required field is missing, the service responds only with
{"success":false,"error":{"code":"INVALID_REQUEST","message":"…"}}, without request_id.
Operations
operation | Request fields | Additional response fields |
|---|---|---|
info | – | version, algorithms, status, uptime_seconds, requests_processed, keys_stored |
keygen | algorithm, optional level | key_id, algorithm, and public_key for key pairs |
aes_encrypt | key_id, plaintext, optional aad | ciphertext, nonce, tag, key_id |
aes_decrypt | key_id, ciphertext, nonce, tag, optional aad | plaintext |
ml_dsa_sign | key_id, message | signature, signature_size |
ml_dsa_verify | public_key, message, signature, level | valid |
ml_kem_encapsulate | public_key, level | ciphertext, shared_secret |
ml_kem_decapsulate | key_id, ciphertext | shared_secret |
export_public_key | key_id | public_key, algorithm |
hkdf | ikm, length, optional salt, info | derived_key |
Fields with binary content are Base64: plaintext, aad, ciphertext, nonce, tag, message,
signature, public_key, shared_secret, ikm, salt, info, derived_key. key_id and length
are numbers.
algorithm and level
| Purpose | Accepted values |
|---|---|
keygen.algorithm | AES-256-GCM, AES256, AES; ML-DSA, ML-DSA-44, ML-DSA-65, ML-DSA-87; ML-KEM, ML-KEM-512, ML-KEM-768, ML-KEM-1024 (case-insensitive) |
level for ML-DSA | ML-DSA-44, ML-DSA-65, ML-DSA-87, ml-dsa-44 …, or just 44, 65, 87 |
level for ML-KEM | ML-KEM-512, ML-KEM-768, ML-KEM-1024, ml-kem-512 …, or just 512, 768, 1024 |
A keygen with ML-DSA or ML-KEM and no level generates ML-DSA-65 or ML-KEM-768. An unknown level
results in UNSUPPORTED_ALGORITHM.
Notes on individual operations
aes_encryptgenerates the nonce itself and returns it in the response. Storenonceandtagwith the ciphertext;aes_decryptneeds both.ml_dsa_verifyreports an invalid signature as a success with"valid": false. Always checkvalid, not justsuccess.hkdf: The service treats asaltorinfothat isn't valid Base64 as empty. Validate the encoding before you send. The maximum output is 8160 bytes (255 × 32).
Example
Request:
{"operation":"keygen","request_id":"k1","algorithm":"ML-KEM","level":"ML-KEM-768"}
Response (shortened):
{"id":"5d1c…","request_id":"k1","timestamp":1760788800000,"success":true,"duration_us":412,"key_id":2741182583,"algorithm":"ML-KEM-768","public_key":"…"}