Skip to content

Commit 2bf71e8

Browse files
authored
Update STRANDLOCK_PROTOCOL.md
1 parent 97cbb03 commit 2bf71e8

File tree

1 file changed

+46
-41
lines changed

1 file changed

+46
-41
lines changed

STRANDLOCK_PROTOCOL.md

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,48 +29,48 @@ If Both `KEMs`, and `xChaCha20Poly1305` are compromised in future, as long as `O
2929

3030
For clarity, the following terms are used consistently throughout this specification:
3131

32-
##### Request
32+
#### Request
3333
A generic protocol message sent from one party to another. A Request is not bound to `HTTP` or any specific transport mechanism; it may be carried over `TCP`, `UDP`, `sockets`, `pipes`, or any `communication medium`.
3434

35-
##### Response
35+
#### Response
3636
The reply to a Request, carrying the necessary protocol data to complete or continue a Strandlock operation.
3737
We use term "Response" and "Request" interchangably. A response is a request.
3838

39-
##### Session
39+
#### Session
4040
A logical state maintained between two parties that tracks shared secrets, nonces, and protocol progress. A session may span multiple Requests and Responses. Only one session is allowed per-contact. This protocol does not (and will not) support multi-devices, nor multi-session per same contact.
4141

42-
##### Strand Nonce
42+
#### Strand Nonce
4343
A cryptographically secure random value used for entropy injection, whitening, and rotation. Strand nonces are exclusively used for `xChaCha20Poly1305` wrapping encryption. Every request contains the next nonce that will be used for the next request. Such nonces we call "Strand Nonces". Alice and Bob both save each other strand nonces.
4444

45-
##### Strand Key
45+
#### Strand Key
4646
Any key material derived, rotated, or combined from multiple primitives within Strandlock. Strand Key is fed to `xChaCha20Poly1305` to "wrap encrypt" everything. Applies to PFS, MSGS requests and responses, but not SMP. SMP process uses a temporary key simply dubbed "Temporary xChaCha key" or "SMP key"
4747

4848

49-
##### SMP (Socialist Millionaire Protocol)
49+
#### SMP (Socialist Millionaire Protocol)
5050
An authentication mechanism used to confirm shared knowledge between two parties without revealing the secret itself.
5151
It does not refer to vanilla SMP, but refers to Off-the-record messaging-style `SMP`.
5252

53-
##### OTP Batch
53+
#### OTP Batch
5454
A collection of one-time pad material derived from multiple primitives and signed before being used for message encryption.
5555

5656
### 2. General Protocol Features
5757

58-
##### Request Types:
58+
#### Request Types:
5959
Every request includes a message type identifier, which may be visible only in the very first `SMP` stage request. For all other requests that come afterwards, the type is encrypted within the payload.
6060

61-
##### Nonces:
61+
#### Nonces:
6262
Each request contains a `24-bytes nonce` immediately following the `type` field. These `nonces` are meant to be used for the next request to prevent metadata leakage, replay attacks, and on the small off-chance that a randomly generated nonce repeats twice, network adversaries wouldn't know a nonce reuse occured.
6363

6464
Additionally, while all public security proofs of `xChaCha20Poly1305` assume nonce is public, encrypting and or hiding the `nonce` might actually "future-proof" `xChaCha20Poly1305` against potentinal future attacks, leaving only open window through pure dumb brute-forcing of `32 bytes` key space.
6565

66-
##### Encryption:
66+
#### Encryption:
6767
All payloads are encrypted with `XChaCha20Poly1305`, except for the `SMP` initiation stage.
6868

69-
##### Human Verification:
69+
#### Human Verification:
7070
`SMP` enforces a human-verifiable question-and-answer process before any chat communication. This prevents "trust on first use"-style attacks that plagues other encrypted protocols.
7171

72-
### 3. SMP (Socialist Millionaire Protocol)
73-
##### 3.1 Initialization (Alice -> Bob)
72+
### 3. Socialist Millionaire Protocol (`SMP`)
73+
#### 3.1 Initialization (`Alice` -> `Bob`)
7474

7575
`Alice` selects an `SMP` question and answer and stores them locally.
7676

@@ -82,7 +82,7 @@ All payloads are encrypted with `XChaCha20Poly1305`, except for the `SMP` initia
8282

8383
The `payload` is prefixed with `SMP_TYPE = 0x00`.
8484

85-
##### 3.2 Response (Bob -> Alice)
85+
#### 3.2 Initialization response (`Bob`)
8686

8787
`Bob` generates a shared secret using `Alice’s` `ML-KEM-1024` public key (this is called temporary xchacha key, only used for `SMP` encryption).
8888

@@ -107,7 +107,7 @@ SMP_TYPE || ALICE_ML_KEM_CIPHERTEXT || SMP_RESPONSE_CIPHERTEXT
107107
`Bob` saves `Alice` to his contact list locally, however `Bob` **must** flag `Alice` as `unverified` or `pending_verification`.
108108
`Bob` also stores all `nonces` and the `temporary XChaCha key` for this `SMP` session.
109109

110-
##### 3.3 Proof 1 (`Alice's` proof of `Bob's` public-key)
110+
#### 3.3 Proof 1 (`Alice's` proof of `Bob's` public-key)
111111

112112
`Alice` decapsulates the KEM ciphertext, derives shared secret to get the "temporary xChaCha key", then she decrypts the `XChaCha` ciphertext using the `temporary xChaCha key`.
113113

@@ -153,7 +153,7 @@ SMP_REQUEST_DATA = SMP_TYPE || NEW_ALICE_STRAND_NONCE || ALICE_SIGNING_PUBLIC_KE
153153

154154
`Alice` encrypts the payload with `XChaCha20` using `temporary xchacha key` as key, and uses `ALICE_NEXT_STRAND_NONCE` as nonce, and sends it to `Bob`
155155

156-
##### 3.4 Verification & Proof 2 (`Bob`):
156+
#### 3.4 Verification & Proof 2 (`Bob`):
157157

158158
`Bob` decrypts the payload with the `temporary key` and asks the user for an `SMP answer`.
159159

@@ -200,7 +200,7 @@ BOB_STRAND_KEY = XOR(BOB_STRAND_KEY, SHA3_512(ANSWER_SECRET))
200200

201201
`Bob` then saves the new keys, and marks `Alice` as `SMP` verified.
202202

203-
##### 3.5 Final Verification (`Alice`):
203+
#### 3.5 Final Verification (`Alice`):
204204

205205
`Alice` decrypts `Bob’s` `SMP` payload and verifies `Bob’s` proof.
206206

@@ -210,7 +210,7 @@ If valid, she applies the same `XOR` transformation to the `Strand Keys`, and sa
210210

211211
`Alice` sends her first PFS keys.
212212

213-
##### 3.6. Notes on SMP:
213+
#### 3.6. Notes on SMP:
214214

215215
Step 1: No encryption
216216

@@ -225,6 +225,8 @@ Do not confuse `Strand Nonces` with `SMP Nonces`, the latter is only used for SM
225225

226226
The security of the `SMP` process depends entirely on the entropy of the user-provided `answer`, we use extreme `Argon2id` parameters to protect against a *"god-like"* adversary with virtually *unlimited* computing power, and we salt the answer to prevent *Rainbow-style* attacks. **However**, if `answer` is *low-entropy*, even such measures cannot completely prevent the cracking of the answer.
227227

228+
Answers don't have to be uncrackable forever, just uncrackable for a reasonable duration (minimum 1 week to months), our extreme `Argon2id` parameters achieve just that.
229+
228230
We highly recommend implementations to only allow user to set a `8+ character` answer, and to check the entropy of provided answer (is all lowercase, is all uppercase, is only digits, etc), and to warn (or prevent) the user from continuing.
229231

230232
Even though the `question` is encrypted, an active *Man-in-the-middle* adversary **can still retrieve it**. The verification would fail, but the adversary would have the `question` plaintext.
@@ -234,45 +236,48 @@ The question **must not** contain any senstive data. And it must not contain any
234236
Implementations **must** check `answer` and `question` in initation stage, to ensure neither contain the other.
235237

236238

237-
### 4. Perfect Forward Secrecy (PFS)
238-
##### 4.1 Key Rotation
239-
240-
Alice checks if a saved ALICE_KEYS_HASH_CHAIN exists:
241-
242-
If not, she generates a new hash chain of size KEYS_HASH_CHAIN_LEN.
243-
244-
Otherwise, she advances the hash chain using SHA3-512.
239+
### 4. Perfect Forward Secrecy (`PFS`)
240+
#### 4.1 Key Rotation (`Alice`)
245241

246-
Alice generates new ML-KEM-1024 key pairs.
242+
`Alice` checks if a saved `ALICE_KEYS_HASH_CHAIN` exists:
243+
- If not, she generates a new hash chain of size `KEYS_HASH_CHAIN_LEN` (default `64 bytes`).
244+
- Otherwise, she advances the hash chain by hashing the previous hash chain with `SHA3-512`, then output truncating to `KEYS_HASH_CHAIN_LEN`.
247245

248-
Alice checks if McEliece keys need rotation (after 10 OTP batches or if never sent before).
246+
`Alice` generates new `ML-KEM-1024` key pairs.
249247

250-
Alice constructs publickeys_hashchain:
248+
`Alice` checks if `Classic-McEliece` keys need rotation (by checking some `rotation_counter` and when it reaches a specific number, say `10`, it means its time to rotate, or, if `Alice` never sent any keys before).
251249

252-
hash_chain || ml_kem_1024_public_key || optional_classic_mceliece_8192128f_public_key
250+
`Alice` constructs `PUBLICKEYS_HASHCHAIN`:
251+
```
252+
hash_chain || ml_kem_1024_public_key || optional_classic_mceliece_8192128_public_key
253+
```
253254

254-
Alice signs publickeys_hashchain with her signing key.
255+
`Alice` signs `PUBLICKEYS_HASHCHAIN` with her signing key.
255256

256-
Alice generates ALICE_NEW_STRAND_NONCE.
257+
`Alice` generates `ALICE_NEW_STRAND_NONCE`.
257258

258-
Alice sends:
259+
`Alice` constructs `PFS` request:
260+
```
261+
PFS_PAYLOAD = PFS_TYPE || ALICE_NEW_STRAND_NONCE || PUBLICKEYS_HASHCHAIN_SIGNATURE || PUBLICKEYS_HASHCHAIN
262+
```
259263

260-
PFS_TYPE || ALICE_NEW_STRAND_NONCE || PUBLICKEYS_HASHCHAIN_SIGNATURE || PUBLICKEYS_HASHCHAIN
264+
`Alice` then encrypts the `PFS_PAYLOAD`, with `xChaCha20Poly1305` using her `ALICE_STRAND_KEY` key, and using previous `ALICE_NEXT_STRAND_NONCE` as nonce.
261265

266+
#### 4.2 Receiving PFS Keys (`Bob`)
262267

263-
Encrypted using previous ALICE_NEXT_STRAND_NONCE.
268+
`Bob` decrypts strand wrapper encryption with `xChaCha20Poly1305` using `ALICE_STRAND_KEY` as key, and `ALICE_NEXT_STRAND_NONCE` as nonce.
264269

265-
4.2 Receiving PFS Keys (Bob)
270+
`Bob` updates `ALICE_NEXT_STRAND_NONCE` with `ALICE_NEW_STRAND_NONCE`.
266271

267-
Bob decrypts using ALICE_STRAND_KEY and ALICE_NEXT_STRAND_NONCE.
272+
`Bob` *verifies* hash chain and signature using `Alice` signing public-key.
268273

269-
Bob updates ALICE_NEXT_STRAND_NONCE.
274+
`Bob` determines which keys were sent (`ML-KEM-1024` only or `ML-KEM-1024` + `Classic-McEliece-8192128`), and saves them.
270275

271-
Bob verifies hash chain and signature.
276+
`Bob` then checks if he already sent keys to `Alice`, if he never sent any keys before to `Alice`, he performs the `4.1. Key Rotation` as well.
272277

273-
Bob determines which keys were sent (ML-KEM-1024 only or ML-KEM + McEliece) and saves them.
278+
#### 4.3. PFS Notes:
279+
Even though the use of hash-chains and signatures may appear redundant here, as we already wrap everything in `xChaCha20Poly1305`, and we encrypt its nonce, which serves as a replay protection, and tamper protection, the use of hash-chains here ensures that even if `xChaCha20Poly1305` is broken, PFS keys cannot be replayed, nor tampered with.
274280

275-
If Bob has no new keys to send, he generates them similarly.
276281

277282
5. Messaging (MSGS)
278283
5.1 OTP Batch Generation

0 commit comments

Comments
 (0)