diff --git a/rpc.md b/rpc.md index 6d70b7fd4232f0417c615dbdd6e03a1fcca5ebc8..e45193bb7766cf84881b8647231a7fda8f655d2b 100644 --- a/rpc.md +++ b/rpc.md @@ -75,7 +75,7 @@ Noise_NK_25519_ChaChaPoly_BLAKE2s This noise protocol uses ECDH asymmetric encryption with XChaCha20Poly1305 symmetric encryption and Blake2s hashes inside of the -protocol. Additionally, the prologue is set to the current DM protocol +protocol. Additionally, the prologue is set to the current RPC protocol version (`0x0 0x0` at the time of this writing). Full details on Noise Protocol and the syntax used above can be found in the [noise specification document](https://noiseprotocol.org/noise.html). @@ -88,25 +88,108 @@ many RPC APIs. ## Reception IDs -The `server` can select it's own reception ID. This can be derived from the +The `server` can select it's own reception ID. This can be derived +from its public key, manually set by the operator, or through some +other method. A pseudorandomly generated ID shall be the +default. Reception of each message will be determined by encrypting +for the server's static key, so using the same reception ID is not a +concern. -... - -The `client` selects a random id determined by the key they generate. This is one-time use.. +The `client` selects a random id determined by the key they +generate. This is a one-time use key and reception ID. For simplicity, +the client shall be live the entire time this temporary reception ID +is in use, so no storage will be necessary to e.g., receive a response +after the client is closed. ## RPC Messages Every RPC message has the following contents of note: -.... +``` +message RPCMessage{ + byte Version = 1; + ... + bytes PubKey = 3; + ... + bytes Ciphertext = 5; + ... + bytes Nonce = 7; +} +``` + +These fields are used as follows: +* `Version` of the rpc message, set to 0x0. +* `PubKey` the public key sent as part of the NK Noise protocol. +* `Ciphertext` of the request or response. +* `Nonce` set by the sender to avoid repeats. Repeated + nonces should be ignored. + +Requests and responses look the same from a cMix packet perspective. ## RPC Encryption +The format of the plaintext inside the RPC ciphertext for the request or the +response uses a message partitioning format: + +``` +plaintext = varuint(len(message)) | varuint(offset) | message +``` + +Where: +* `varuint` is a variable length integer encoding of an unsigned integer. +* `len` is the length function. +* `offset` number of bytes into the message that this part represents. +* `message` the contents of the request or response. + ### Request +The sender client creates and encrypts the request plaintext as follows: + +``` +requestPublicKey, requestPrivateKey = generateKeyPair(rng) +key = H(DH(requestPrivateKey, RPCServerStaticPublicKey)) +ciphertext = NoiseNK.Encrypt(key, plaintext) +``` + ### Response +The server creates and encrypts the plaintext response as follows: + +``` +responsePublicKey, responsePrivateKey = generateKeyPair(rng) +key = H(DH(responsePrivateKey, requestPublicKey)) +ciphertext = NoiseNK.Encrypt(key, plaintext) +``` ## Security Considerations + +The cMix protocol is providing the metadata protection and Noise is +providing all of the core confidentiality properties. A nonce and timestamp +prevent excessive resending of the same request and replays. + +Requests are encryption to a known recipient, which provides forward +secrecy for sender compromise only. Without the nonce this message can +be replayed, since there's no ephemeral contribution from the +recipient. + +For requests, the payload is also encrypted based only on DHs +involving the recipient's static key pair. If the server's static +private key is compromised, even at a later date, this payload can be +decrypted. You can mitigate by rotating the key, creating keys for +specific users, or another method. + +Responses are encryption to an ephemeral recipient, so the payload has +forward secrecy as the encryption involves an ephemeral-ephemeral DH +(`ee`). However, the sender cannot authenticate the recipient, which +means the RPC server must treat all requests as untrusted. This could +be used to exhaust resources, but can be mitigated with anonymized api +keys, paid return postage, or another mechanism. + +The identity of the requestor remains protected in all cases because +it is not transmitted. It is important that the RPC protocol itself +not add information which could be used to break this protection. The +server also enjoys significant protection but is using a "public" +address in practice, so while it's physical location is protected its +cMix address is protected via recipient ID collisions.