@@ -252,3 +252,98 @@ Sharing a secret means sending the some information about the `Allocation` objec
252252which bytes in which blocks have been allocated, but not the byte values themselves.
253253The peer then uses this information to create a corresponding ` Allocation ` object with
254254identical byte values.
255+
256+ ## Message authentication
257+
258+ The DSKE protocol runs over HTTP and not over HTTPS;
259+ it uses its own authentication and encryption mechanisms instead of relying on TLS.
260+
261+ In-band DSKE protocol messages are signed using PSRD data for authentication.
262+
263+ The client signs outgoing HTTP request messages and the hub verifies the signature on incoming
264+ HTTP request messages.
265+ The hub signs outgoing HTTP response message and the client verifies the signature on incoming
266+ HTTP response messages.
267+
268+ The sender of an HTTP message signs outgoing HTTP messages as follows:
269+
270+ * Allocate a 32 (SIGNING_KEY_SIZE) byte signing key from the local pool associated with the
271+ received of the message.
272+
273+ * Compute a SHA256 hash over the concatenation of the allocated signing key and the content of
274+ the signed HTTP message and the parameters of the request. This hash is used as the signature.
275+
276+ * Convey the base64 encoded signature in the HTTP header ` DSKE-Signature ` .
277+
278+ * Convey the meta-data of the signing key in the HTTP header ` DSKE-Signing-Key ` .
279+ This allows the receiver to allocate the same signing key from the Pre-Shared Random Data
280+ to verify the signature.
281+ The encoding of the signing key meta data into an HTTP header is described below.
282+
283+ The received of an HTTP message verifies the signature on incoming HTTP messages as follows:
284+
285+ * Extract the meta-data of the signing key from received HTTP header ` DSKE-Signing-Key ` .
286+
287+ * Use this meta data to take the signing key value from the pool of Pre-Shared Random Data.
288+
289+ * Compute a SHA256 hash over the concatenation of the allocated signing key and the content of
290+ the signed HTTP message and the parameters of the request.
291+ This hash is the locally computed signature.
292+
293+ * Compare the locally computed signature with the signature received in the HTTP header
294+ ` DSKE-Signature ` . If they match, the signature is correct.
295+
296+ * If the signatures do not match, the locally allocated signing key is given back to the pool.
297+ This is to prevent Denial-of-Service attacks from an attacker guessing singing keys.
298+
299+ The meta-data of the signing key is encoded into the ` DSKE-Signing-Key ` header as follows:
300+
301+ * One or more encoded fragment meta-data strings, separated by commas.
302+
303+ * Each fragment meta-data string is encoded as the block UUID, the start byte within the block,
304+ and the size of the fragment, separated by colons.
305+
306+ * Note that the key data (fragment data) is not encoded into the meta-data.
307+
308+ Example of an encoded signing key meta-data (consisting of two fragments, one fragment
309+ of 20 bytes, and another fragment of a different block of 12 bytes):
310+
311+ ```
312+ 9ad7f620-5a0c-4979-8a2d-66142e06fd79:0:20,cda527e9-5ca7-40d6-a842-0b606597611c:0:12
313+ ```
314+
315+ The signatures have to be computed over the body of the HTTP message, exactly as it is encoded
316+ in the HTTP message.
317+ This was non-trivial to implement in the code.
318+
319+ On the client side, we use the Python
320+ [ httpx] ( https://www.python-httpx.org/ )
321+ module.
322+ On the server (hub) side, we use the Python
323+ [ FastAPI] ( https://fastapi.tiangolo.com/ )
324+ module.
325+ Both modules try to make life easier for the developer by allowing the code to use Python objects
326+ (instead of raw bytes or strings) to represent the body of a message.
327+ However, to compute the signature we needed the exact encoded bytes in the HTTP message, not
328+ its representation as a Python object.
329+ We could have tried to work with canonical encoders/decoders, but that would be complex and
330+ error-prone.
331+ Instead, we used a different mechanism to get access to the encoded message body and
332+ compute/verify the signature over it.
333+
334+ On the client (httpx) side, we use the
335+ [ per-request authentication mechanism] ( https://www.python-httpx.org/advanced/authentication/ )
336+ to register a ` async_auth_flow ` callback.
337+ This callback is called after the message is encoded but before it is sent.
338+ This allows us to compute the signature and add the ` DSKE-Signature ` header on the outgoing
339+ HTTP request.
340+
341+ On the hub (server, FastAPI) side, we use the
342+ [ Starlette middleware mechanism] ( https://www.starlette.dev/middleware/ ) .
343+ We register the ` dske_authentication ` function as a middleware for HTTP.
344+ This gives us access to the body in a request before decoding and the body in a response
345+ before encoding.
346+
347+ ## Share encryption
348+
349+ TODO
0 commit comments