schastsp/PROTOCOL.md

12 KiB
Raw Blame History

Stateless Time Scrambling Protocol

Motivation

After designing some APIs, I found out that you must have at some point a token system where the token is a fixed-length string. An easy MITM attack could be to repeat a previously sent request while the token is still valid. Or in worse conditions, catch the client token and build a malicious request with its authenticated session.

In the rest of this document we will admit that what travels through the network is public, so any MITM can store it. Obviously I highly recommend using TLS for communicating, but we look here for a consistent token system, it only can be better through TLS.

A good solution could be to use a one-time token so the server sends back a new token for each response. This behavior means that the token travels through the network - which we consider public - before being used. In addition we would like the server to create only a secret key once to fasten the authentication system, because it could manage millions of clients.

A better solution would be to keep a private key and wrap it in a one-time system that generates a public token for each request. It would avoid attackers to repeat our requests or guess the private key from the token. Also short-lived one-time passwords have a mechanism that we could use to build a time-dependent system.

What we need

  1. Generate a public token for each request from a fixed private key
  2. The public token never to be the same
  3. Each public token to be only valid a few seconds after sending it
  4. Each public token to give no clue that could help guessing the next token.
  5. A system where the server does not have to share a private key with each client and does not need to.

Technology requirements

  1. Mixing 2 hashes in a way that without one of them, the other is cryptographically impossible to guess (i.e. one-time pad).
  2. Having a time-dependent unique hash, that could be found only a few seconds after sending it (as for TOTP).
  3. A cryptographic hash function that, from an input of any length, outputs a fixed-length digest in a way that is impossible to guess the input back from it.

Protocols to define

This document will define and bundle 2 distinct protocols to implement a token system that implements the previous statements.

  1. a Stateless Time Scrambling Protocol to take care of the request's expiration over time
  2. a Stateless Cyclic Hash Algorithm to generate several public keys from a single secret key in a way that no clue is given over published keys.

General knowledge & Notations

Notation
Symbols Description
\parallel a\parallel The absolute value of a ; e.g. \parallel a \parallel = \parallel -a \parallel
\mid a \mid The integer value of a ; e.g. \mid 12.34 \mid = 12
a \oplus b The bitwise operation XOR between binary words a and b
h(m) The digest of the message m by a consistent cryptographic hashing function h() ; e.g. sha512
h^n(m) The digest of the n-recursive hashing function h() with the input data m ; e.g. h^2(m) \equiv h(h(m)) , h^1(m) \equiv h(m) and h^0(m) \equiv m.
a \mod b The result of a modulo b ; i.e. the remainder of the Euclidean division of a by b
T_{now} The current Unix Timestamp in seconds
Entities
  • A machine C (typically a client)
  • A machine S (typically a server)
Common variables

These variables are both on the server and clients. They are specific to the server so each client must match these.

Notation Name Description
W time window divider A fixed number of seconds that is typically the maximum transmission time from end to end.
Client variables

These variables defines the state of each client, each having different values.

Notation Name Description
K shifting key The client private key. It is only known by the client, it must be large enough not to be brute forced.
n_0 shifting nonce A private number that is decremented for each request. It is unique to each private key K. Before n_0 reaches 0, a new key K must be generated and n_0 is set to its higher value.
s next request order The next request order is a number that, according on its value, will change the client's behavior :
- 0 : normal request
- 1 : new key generated
- 2 : rescue mode (resynchronize with the server)
Server variables
Notation Name Description
H last valid hash The server stores the last valid hash from the client to check the next one.

If a client sends its token h^{n_0}(K), if the token is valid the server stores it inside H.

Note that for the first synchronization, the server has to "blindly" consider the token as valid.

When the client sends its next token h^{n_0-1}(K), the server has to hash it and compare it with the last token H.

h(h^{n_0-1}) = h^{n_0}(K)

Description of the problem

C wants to send a token that will only be valid one time and within a fixed time window.

Note: This document only gives a solution for the time-dependent feature, the one-time aspect is wrapped into the implementation of the f() function. If you only need the time-dependent feature, you can set f(x, n^1) to always return x so the key K will be only protected by the time protection algorithm.

Constraints
  • S must be able to recover the token if the data is received within the time window.
  • If the window expired, the token must be invalidated by the server.
Limitations
  • If an arbitrary catches, then blocks a request from C to S and sends it afterwards, it will be authenticated. This case is equivalent to being C (with all secret variables), which can never occur if you use TLS. Notice that you won't be able to extract anything from the token anyway.
  • With requests meta data (e.g. HTTP headers containing the date), an attacker knowing W can forge the time hash h_n and be able to recover the private key K by processing a simple XOR on the public token. Because the cyclic-hash algorithm generates a unique pseudo-random token from K for each request, this case does not give the attacker any clue about the next token to be sent.

Protocol

Each request and response will hold a pair of tokens.

1. Client request

This case is the default one where n_0 is far from 1 so there is no key generation to do.

Step Description Formula
c1 Decrement the shifting nonce n_0 = n_0 - 1
c2 Calculate the one-time token T_C T_C = h^{n_0}(K)
c3 Get the current window id n_C n_C =\ \mid \frac{T_{now}}{W} \mid
c4 Calculate m_C, the parity of n_C m_C = n_C \mod 2
c5 Calculate the time hash h_{n_C} h_{n_C} = h(n_C)
c6 Calculate T_{req}, the scrambled request token T_{req} = T_C \oplus h_{n_C}

Steps explanation

  • c2 - The window id corresponds to the index of the time slice where slices are W seconds wide. By dividing the time in slices of W seconds, if we process the same calculation at an interval of W or less seconds, we will have either the same result or a result greater by 1.
  • c3 - The window id parity m_C allows us to adjust the value of n_S made on S when it receives the request. This difference of 1 second is caused by the division of time in slices, the precision is also divided by W.
    • T_{now}\mod W = 0 \implies \mid \frac{T_{now}}{W} \mid = \mid \frac{T_{now}+(W-1)}{W} \mid; no need for adjustment
    • T_{now}\mod W = 1 \implies \mid \frac{T_{now}}{W} \mid = \mid \frac{T_{now}+(W-1)}{W} \mid + 1; need to subtract 1
    • T_{now}\mod W = 2 \implies \mid \frac{T_{now}}{W} \mid = \mid \frac{T_{now}+(W-1)}{W} \mid + 1; need to subtract 1
    • ...
    • T_{now}\mod W = (W-1) \implies \mid \frac{T_{now}}{W} \mid = \mid \frac{T_{now}+(W-1)}{W} \mid + 1; need to subtract 1
  • c4 - h(n_C) allows h_{n_C} to be L bits long and protects n_C to be predictable from h_{n_C}.
  • c5 - we process a one-time pad between T_C and h_{n_C} it is crucial that both values have the same size of L bits. It makes T_C impossible to extract without having the value h_{n_C}, this property applies in both ways.

Short formulas

Field to send Short formula
T_{req} h^{n_0}(K) \oplus h(\mid\frac{T_{now}}{W}\mid)
m_C \mid\frac{T_{now}}{W}\mid \mod 2

Note

  • In order to send all the data in one request, for instance you can simply concatenate the 2 variables.

2. Server check

Received data

  • T_{req} the received request token
  • m_C the received time id parity
Step Description Formula
s1 Store the reception time window id n' n' = \mid \frac{T_{now}}{W}\mid
s2 Calculate m_S, the parity of n' m_S = n' \mod 2
s3 Use m_C to try to correct the reception window id and guess the request time id n_S = n' - \parallel m_C - m_S \parallel
s4 Calculate the time hash h_{n_S} h_{n_S} = h(n_S)
s5 Cancel h_{n_S} to extract T_{C'} T_{C'} = T_{req} \oplus h_{n_S}
s6 Check if T_{C'} matches T_S T_{C'} = T_S ?

If T_{C'} = T_S, S can consider that C sent the request 0 to (W + \frac{W}{2}) seconds ago.

Steps explanation

  • s1 - If C and S have the same values for K and n^1, f(K,n^1) must result in the same output; in other words T_C=T_S.

  • s3/s4 - \| m_C - m_s\| is the difference between m_C and m_S.

  • If the receiver time window id (n') is the same as the sender (n_C)

    n'=n_C \implies m_S=m_C

    m_C=m_S \implies \| m_C - m_S\| = 0

    n_S = n_C - 0

    n_S=n_C, the time ids are the same, S can now unscramble the request to check the token

    • If the receiver time window if further the sender by 1

      n'=n_C+1 \implies \| m_C - m_S \| = 1

      n_S = n_C + 1 - 1

      n_S = n_C, the time ids are the same, S can now unscramble the request to check the token

    • If the receiver time window if further the sender by 2 or more, let k \in \N

      n'= n_C+2+k \implies \parallel m_C - m_S\parallel \in \{0,1\}

      - \parallel m_C - m_S\parallel \in \{-1,0\}

      n_S \in \{n_C + 2 + k - 1, n_C + 2 + k + 0\}

      n_S \in \{n_C + k + 1, n_C + k + 2\}

      \rarr n_S = n_C + k + 1 \implies \forall (k\in \N), n_S \gt n_C, the time ids differ, S cannot extract T_S

      \rarr n_S = n_C + k + 2 \implies \forall (k \in \N), n_S \gt n_C+1, the time ids differ, S cannot extract T_S

  • s6 - By the non-idempotency (i.e. a\oplus b \oplus a = b) and associativity properties of the XOR operator, considering h_{n_S}=h_{n_C}:

    T_{C'} = T_{req} \oplus h_{n_S} = (T_C \oplus h_{n_C}) \oplus h_{n_S}

    h_{n_S} = h_{n_C} \implies T_{C'} = T_C \oplus h_{n_C} \oplus h_{n_C}

    T_{C'} = T_C, the one-time token of C have successfully been extracted

  • s7 - If K and n^1 are the same on both machines, T_S=T_C. Furthermore, if the time ids are the same (c.f. step s6) the 2 tokens should match.

Short formulas

The whole unscrambling process can be shortened into the following formula resulting in 0 if the client is authenticated.

T_{req} \oplus h(\mid \frac{T_{now}}{W}\mid - \parallel m_C - (\mid \frac{T_{now}}{W}\mid \mod 2) \parallel) \oplus f(K, n^1)