mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-03-08 06:28:18 +01:00
akwizgran created page: BTP
47
BTP.markdown
47
BTP.markdown
@@ -4,7 +4,7 @@ The underlying transport is not required to provide any security properties. We
|
||||
|
||||
### Notation
|
||||
|
||||
We use *||* to denote concatenation, double quotes to denote a UTF-8 string, *int(b, x)* to denote *x* represented as a *b*-bit two's complement big-endian integer, *len(m)* to denote the length of *m* in bytes, and *pack(m)* as shorthand for *int(64, len(m)) || m*.
|
||||
We use *||* to denote concatenation, double quotes to denote a UTF-8 string, *int64(x)* to denote *x* represented as a 64-bit two's complement big-endian integer, *len(m)* to denote the length of *m* in bytes, and *pack(m)* as shorthand for *int64(len(m)) || m*.
|
||||
|
||||
### Crypto primitives
|
||||
|
||||
@@ -53,10 +53,10 @@ The length of each rotation period is *R = D + L*. Rotation periods are aligned
|
||||
|
||||
The initial keys derived from *S* are the keys for period *P - 1*. The keys for each subsequent period *i* are derived from the previous period's keys as follows:
|
||||
|
||||
* *next_ock = KDF(ock, "ROTATE_OUTGOING_CIPHER_KEY", int(64, i))*
|
||||
* *next_ick = KDF(ick, "ROTATE_INCOMING_CIPHER_KEY", int(64, i))*
|
||||
* *next_otk = KDF(otk, "ROTATE_OUTGOING_TAG_KEY", int(64, i))*
|
||||
* *next_itk = KDF(itk, "ROTATE_INCOMING_TAG_KEY", int(64, i))*
|
||||
* *next_ock = KDF(ock, "ROTATE_OUTGOING_CIPHER_KEY", int64(i))*
|
||||
* *next_ick = KDF(ick, "ROTATE_INCOMING_CIPHER_KEY", int64(i))*
|
||||
* *next_otk = KDF(otk, "ROTATE_OUTGOING_TAG_KEY", int64(i))*
|
||||
* *next_itk = KDF(itk, "ROTATE_INCOMING_TAG_KEY", int64(i))*
|
||||
|
||||
If a sender starts sending a stream at time *t* according to the sender's clock, the recipient may start receiving it at any time between *t - D* and *t + D + L* according to the recipient's clock. Therefore each device must retain the incoming keys for the previous, current and next rotation periods, along with the outgoing keys for the current rotation period.
|
||||
|
||||
@@ -64,6 +64,8 @@ If a sender starts sending a stream at time *t* according to the sender's clock,
|
||||
|
||||
Each stream starts with a pseudo-random tag. The recipient calculates the tag in advance and uses it to recognise which sender the stream comes from and which key should be used to authenticate and decrypt it.
|
||||
|
||||
The tag for the *i^th* stream from a given sender to a given recipient in a given rotation period is equal to the first *tag_len* bytes of *MAC(k, int64(i))*, where *k* is *otk* for the sender and *itk* for the recipient. We require that *mac_len >= tag_len*.
|
||||
|
||||
For each sender, the recipient keeps three reordering windows: one for each of the previous, current and next rotation periods. Reordering windows allow streams to be recognised if they are received out of order due to reordering or loss by the underlying transport.
|
||||
|
||||
Each window contains *W* tags, each of which is marked as expected or received. When an expected tag is marked as received, the window slides according to the following rules:
|
||||
@@ -73,4 +75,37 @@ Each window contains *W* tags, each of which is marked as expected or received.
|
||||
|
||||
If the window slides past a tag before it is received, the tag can no longer be recognised. Larger values of *W* make it possible to tolerate more reordering and loss by the underlying transport, but require the recipient to store larger windows.
|
||||
|
||||
The tag for the *i'th* stream from a given sender to a given recipient in a given rotation period is equal to the first *tag_len* bytes of *MAC(k, int(64, i))*, where *k* is *otk* for the sender and *itk* for the recipient. We require that *mac_len >= tag_len*.
|
||||
To avoid reusing tags, which would allow the adversary to identify BTP traffic, the sender must persistently store the number of streams sent to each recipient in the current rotation period. To avoid accepting replayed streams, the recipient must persistently store the reordering window for each sender in the previous, current and next rotation periods.
|
||||
|
||||
### Stream header
|
||||
|
||||
The pseudo-random tag is followed by the stream header, which contains a random nonce and an ephemeral cipher key encrypted and authenticated with the rotating cipher key and the nonce. The length of the stream header is *nonce_len + key_len + auth_len* bytes. The ephemeral cipher key is used for encrypting and authenticating the rest of the stream.
|
||||
|
||||
### Frames
|
||||
|
||||
The remainder of the stream consists of one or more frames. Each frame has a fixed-length header and a variable-length body that may contain data, padding, neither or both. The frames are numbered starting from zero. No more than 2^63 frames may be sent in a single stream.
|
||||
|
||||
The plaintext frame header is 4 bytes long with the following format:
|
||||
|
||||
* Bit 0: Final frame flag, set to one if this is the last frame in the stream
|
||||
* Bits 1-15: Length of the data in bytes as a big-endian integer
|
||||
* Bit 16: Zero
|
||||
* Bits 17-31: Length of the padding in bytes as a big-endian integer
|
||||
|
||||
The total length of the data and padding must be less than 2^15 bytes.
|
||||
|
||||
The plaintext frame body contains the data and padding. If any padding is present it must all be zeroes.
|
||||
|
||||
The header and body are encrypted and authenticated separately using the ephemeral cipher key and deterministic nonces, which are not sent.
|
||||
|
||||
The nonce for the frame header is *nonce_len* bytes long with the following format:
|
||||
|
||||
* Bit 0: Header flag, set to one
|
||||
* Bits 1-63: Frame number as a big-endian integer
|
||||
* Remaining bits: Zero
|
||||
|
||||
The nonce for the frame body is *nonce_len* bytes long with the following format:
|
||||
|
||||
* Bit 0: Header flag, set to zero
|
||||
* Bits 1-63: Frame number as a big-endian integer
|
||||
* Remaining bits: Zero
|
||||
|
||||
Reference in New Issue
Block a user