From a5ca0ae2ee5c80106e578b6fbc10069cc84b0f01 Mon Sep 17 00:00:00 2001 From: "Richard T. Carback III" <rick.carback@gmail.com> Date: Mon, 13 May 2024 13:21:38 -0400 Subject: [PATCH] Initial RPC draft I left some brokenness in the packet format section and I believe the security considerations probably needs a second look. It's just not exactly clear what the separation should be between the packet encryption format and the larger cMix message type, and my incliniation is to not have an RPCMessage type at all. --- rpc.md | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/rpc.md b/rpc.md index 6d70b7f..e45193b 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. -- GitLab